prostgles-server 3.0.49 → 3.0.51
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/dist/DboBuilder/TableHandler.d.ts +3 -11
- package/dist/DboBuilder/TableHandler.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler.js +0 -74
- package/dist/DboBuilder/TableHandler.js.map +1 -1
- package/dist/DboBuilder/ViewHandler.d.ts +9 -1
- package/dist/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler.js +127 -0
- package/dist/DboBuilder/ViewHandler.js.map +1 -1
- package/dist/DboBuilder/runSQL.d.ts.map +1 -1
- package/dist/DboBuilder/runSQL.js +23 -3
- package/dist/DboBuilder/runSQL.js.map +1 -1
- package/dist/DboBuilder.d.ts +10 -0
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js.map +1 -1
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +10 -0
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager.d.ts +10 -2
- package/dist/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager.js +83 -75
- package/dist/PubSubManager.js.map +1 -1
- package/lib/DboBuilder/TableHandler.d.ts +1 -9
- package/lib/DboBuilder/TableHandler.d.ts.map +1 -1
- package/lib/DboBuilder/TableHandler.js +0 -74
- package/lib/DboBuilder/TableHandler.ts +2 -86
- package/lib/DboBuilder/ViewHandler.d.ts +9 -1
- package/lib/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/lib/DboBuilder/ViewHandler.js +127 -0
- package/lib/DboBuilder/ViewHandler.ts +157 -2
- package/lib/DboBuilder/runSQL.d.ts.map +1 -1
- package/lib/DboBuilder/runSQL.js +23 -3
- package/lib/DboBuilder/runSQL.ts +24 -3
- package/lib/DboBuilder.d.ts +10 -0
- package/lib/DboBuilder.d.ts.map +1 -1
- package/lib/DboBuilder.ts +15 -2
- package/lib/Prostgles.d.ts.map +1 -1
- package/lib/Prostgles.js +10 -0
- package/lib/Prostgles.ts +11 -0
- package/lib/PubSubManager.d.ts +10 -2
- package/lib/PubSubManager.d.ts.map +1 -1
- package/lib/PubSubManager.js +83 -75
- package/lib/PubSubManager.ts +104 -82
- package/package.json +2 -2
- package/tests/client/PID.txt +1 -1
- package/tests/isomorphic_queries.js +2 -2
- package/tests/isomorphic_queries.ts +2 -2
- package/tests/server/package-lock.json +3 -3
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TableHandler = void 0;
|
|
4
4
|
const prostgles_types_1 = require("prostgles-types");
|
|
5
5
|
const DboBuilder_1 = require("../DboBuilder");
|
|
6
|
-
const PubSubManager_1 = require("../PubSubManager");
|
|
7
6
|
const delete_1 = require("./delete");
|
|
8
7
|
const insert_1 = require("./insert");
|
|
9
8
|
const insertDataParse_1 = require("./insertDataParse");
|
|
@@ -59,79 +58,6 @@ class TableHandler extends ViewHandler_1.ViewHandler {
|
|
|
59
58
|
return true;
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
|
-
async subscribe(filter, params = {}, localFunc, table_rules, localParams) {
|
|
63
|
-
try {
|
|
64
|
-
if (this.is_view)
|
|
65
|
-
throw "Cannot subscribe to a view";
|
|
66
|
-
if (this.t)
|
|
67
|
-
throw "subscribe not allowed within transactions";
|
|
68
|
-
if (!localParams && !localFunc)
|
|
69
|
-
throw " missing data. provide -> localFunc | localParams { socket } ";
|
|
70
|
-
if (localParams && localParams.socket && localFunc) {
|
|
71
|
-
console.error({ localParams, localFunc });
|
|
72
|
-
throw " Cannot have localFunc AND socket ";
|
|
73
|
-
}
|
|
74
|
-
const { filterFields, forcedFilter } = table_rules?.select || {}, filterOpts = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }), condition = filterOpts.where, throttle = params?.throttle || 0, selectParams = (0, PubSubManager_1.omitKeys)(params || {}, ["throttle"]);
|
|
75
|
-
/** app_triggers condition field has an index which limits it's value */
|
|
76
|
-
const filterSize = JSON.stringify(filter || {}).length;
|
|
77
|
-
if (filterSize * 4 > 2704) {
|
|
78
|
-
throw "filter too big. Might exceed the btree version 4 maximum 2704. Use a primary key or a $rowhash filter instead";
|
|
79
|
-
}
|
|
80
|
-
if (!localFunc) {
|
|
81
|
-
if (!this.dboBuilder.prostgles.isSuperUser)
|
|
82
|
-
throw "Subscribe not possible. Must be superuser to add triggers 1856";
|
|
83
|
-
return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
|
|
84
|
-
.then(async (isValid) => {
|
|
85
|
-
const { socket } = localParams ?? {};
|
|
86
|
-
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
87
|
-
return pubSubManager.addSub({
|
|
88
|
-
table_info: this.tableOrViewInfo,
|
|
89
|
-
socket,
|
|
90
|
-
table_rules,
|
|
91
|
-
condition: condition,
|
|
92
|
-
func: undefined,
|
|
93
|
-
filter: { ...filter },
|
|
94
|
-
params: { ...selectParams },
|
|
95
|
-
socket_id: socket?.id,
|
|
96
|
-
table_name: this.name,
|
|
97
|
-
throttle,
|
|
98
|
-
last_throttled: 0,
|
|
99
|
-
}).then(channelName => ({ channelName }));
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
104
|
-
pubSubManager.addSub({
|
|
105
|
-
table_info: this.tableOrViewInfo,
|
|
106
|
-
socket: undefined,
|
|
107
|
-
table_rules,
|
|
108
|
-
condition,
|
|
109
|
-
func: localFunc,
|
|
110
|
-
filter: { ...filter },
|
|
111
|
-
params: { ...selectParams },
|
|
112
|
-
socket_id: undefined,
|
|
113
|
-
table_name: this.name,
|
|
114
|
-
throttle,
|
|
115
|
-
last_throttled: 0,
|
|
116
|
-
}).then(channelName => ({ channelName }));
|
|
117
|
-
const unsubscribe = async () => {
|
|
118
|
-
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
119
|
-
pubSubManager.removeLocalSub(this.name, condition, localFunc);
|
|
120
|
-
};
|
|
121
|
-
let res = Object.freeze({ unsubscribe });
|
|
122
|
-
return res;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (e) {
|
|
126
|
-
if (localParams && localParams.testRule)
|
|
127
|
-
throw e;
|
|
128
|
-
throw (0, DboBuilder_1.parseError)(e, `dbo.${this.name}.subscribe()`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
subscribeOne(filter, params = {}, localFunc, table_rules, localParams) {
|
|
132
|
-
let func = localParams ? undefined : (rows) => localFunc(rows[0]);
|
|
133
|
-
return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
|
|
134
|
-
}
|
|
135
61
|
async updateBatch(data, params, tableRules, localParams) {
|
|
136
62
|
try {
|
|
137
63
|
const queries = await Promise.all(data.map(async ([filter, data]) => await this.update(filter, data, { ...(params || {}), returning: undefined }, tableRules, { ...(localParams || {}), returnQuery: true })));
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import pgPromise from "pg-promise";
|
|
2
|
-
import { AnyObject, asName, DeleteParams, FieldFilter, getKeys, InsertParams,
|
|
2
|
+
import { AnyObject, asName, DeleteParams, FieldFilter, getKeys, InsertParams, isObject, Select, SelectParams, UpdateParams } from "prostgles-types";
|
|
3
3
|
import { DboBuilder, Filter, LocalParams, makeErr, parseError, TableHandlers, TableSchema } from "../DboBuilder";
|
|
4
4
|
import { DB } from "../Prostgles";
|
|
5
|
-
import { SyncRule, TableRule
|
|
6
|
-
import { omitKeys } from "../PubSubManager";
|
|
5
|
+
import { SyncRule, TableRule } from "../PublishParser";
|
|
7
6
|
import { _delete } from "./delete";
|
|
8
7
|
import { insert } from "./insert";
|
|
9
8
|
import { insertDataParse } from "./insertDataParse";
|
|
@@ -61,89 +60,6 @@ export class TableHandler extends ViewHandler {
|
|
|
61
60
|
}
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
async subscribe(filter: Filter, params: SubscribeParams, localFunc: (items: AnyObject[]) => any): Promise<{ unsubscribe: () => any }>
|
|
65
|
-
async subscribe(filter: Filter, params: SubscribeParams, localFunc?: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>
|
|
66
|
-
async subscribe(filter: Filter, params: SubscribeParams = {}, localFunc?: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams):
|
|
67
|
-
Promise<string | { unsubscribe: () => any }> {
|
|
68
|
-
try {
|
|
69
|
-
if (this.is_view) throw "Cannot subscribe to a view";
|
|
70
|
-
if (this.t) throw "subscribe not allowed within transactions";
|
|
71
|
-
if (!localParams && !localFunc) throw " missing data. provide -> localFunc | localParams { socket } ";
|
|
72
|
-
if (localParams && localParams.socket && localFunc) {
|
|
73
|
-
console.error({ localParams, localFunc })
|
|
74
|
-
throw " Cannot have localFunc AND socket ";
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const { filterFields, forcedFilter } = table_rules?.select || {},
|
|
78
|
-
filterOpts = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }),
|
|
79
|
-
condition = filterOpts.where,
|
|
80
|
-
throttle = params?.throttle || 0,
|
|
81
|
-
selectParams = omitKeys(params || {}, ["throttle"]);
|
|
82
|
-
|
|
83
|
-
/** app_triggers condition field has an index which limits it's value */
|
|
84
|
-
const filterSize = JSON.stringify(filter || {}).length;
|
|
85
|
-
if (filterSize * 4 > 2704) {
|
|
86
|
-
throw "filter too big. Might exceed the btree version 4 maximum 2704. Use a primary key or a $rowhash filter instead"
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!localFunc) {
|
|
90
|
-
if (!this.dboBuilder.prostgles.isSuperUser) throw "Subscribe not possible. Must be superuser to add triggers 1856";
|
|
91
|
-
return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
|
|
92
|
-
.then(async isValid => {
|
|
93
|
-
|
|
94
|
-
const { socket } = localParams ?? {};
|
|
95
|
-
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
96
|
-
return pubSubManager.addSub({
|
|
97
|
-
table_info: this.tableOrViewInfo,
|
|
98
|
-
socket,
|
|
99
|
-
table_rules,
|
|
100
|
-
condition: condition,
|
|
101
|
-
func: undefined,
|
|
102
|
-
filter: { ...filter },
|
|
103
|
-
params: { ...selectParams },
|
|
104
|
-
socket_id: socket?.id,
|
|
105
|
-
table_name: this.name,
|
|
106
|
-
throttle,
|
|
107
|
-
last_throttled: 0,
|
|
108
|
-
}).then(channelName => ({ channelName }));
|
|
109
|
-
}) as string;
|
|
110
|
-
} else {
|
|
111
|
-
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
112
|
-
pubSubManager.addSub({
|
|
113
|
-
table_info: this.tableOrViewInfo,
|
|
114
|
-
socket: undefined,
|
|
115
|
-
table_rules,
|
|
116
|
-
condition,
|
|
117
|
-
func: localFunc,
|
|
118
|
-
filter: { ...filter },
|
|
119
|
-
params: { ...selectParams },
|
|
120
|
-
socket_id: undefined,
|
|
121
|
-
table_name: this.name,
|
|
122
|
-
throttle,
|
|
123
|
-
last_throttled: 0,
|
|
124
|
-
}).then(channelName => ({ channelName }));
|
|
125
|
-
const unsubscribe = async () => {
|
|
126
|
-
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
127
|
-
pubSubManager.removeLocalSub(this.name, condition, localFunc)
|
|
128
|
-
};
|
|
129
|
-
let res: { unsubscribe: () => any } = Object.freeze({ unsubscribe })
|
|
130
|
-
return res;
|
|
131
|
-
}
|
|
132
|
-
} catch (e) {
|
|
133
|
-
if (localParams && localParams.testRule) throw e;
|
|
134
|
-
throw parseError(e, `dbo.${this.name}.subscribe()`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/* This should only be called from server */
|
|
139
|
-
subscribeOne(filter: Filter, params: SubscribeParams, localFunc: (item: AnyObject) => any): Promise<{ unsubscribe: () => any }>
|
|
140
|
-
subscribeOne(filter: Filter, params: SubscribeParams, localFunc: (item: AnyObject) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>
|
|
141
|
-
subscribeOne(filter: Filter, params: SubscribeParams = {}, localFunc: (item: AnyObject) => any, table_rules?: TableRule, localParams?: LocalParams):
|
|
142
|
-
Promise<string | { unsubscribe: () => any }> {
|
|
143
|
-
let func = localParams ? undefined : (rows: AnyObject[]) => localFunc(rows[0]);
|
|
144
|
-
return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
63
|
|
|
148
64
|
async updateBatch(data: [Filter, AnyObject][], params?: UpdateParams, tableRules?: TableRule, localParams?: LocalParams): Promise<any> {
|
|
149
65
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as pgPromise from 'pg-promise';
|
|
2
|
-
import { ColumnInfo, FieldFilter, SelectParams, OrderBy, TableInfo as TInfo, AnyObject } from "prostgles-types";
|
|
2
|
+
import { ColumnInfo, FieldFilter, SelectParams, OrderBy, TableInfo as TInfo, AnyObject, SubscribeParams } from "prostgles-types";
|
|
3
3
|
import { DB, DBHandlerServer, Join } from "../Prostgles";
|
|
4
4
|
import { DboBuilder, ExistsFilterConfig, Filter, JoinInfo, LocalParams, SortItem, TableHandlers, TableSchema, ValidatedTableRules } from "../DboBuilder";
|
|
5
5
|
import { Graph } from "../shortestPath";
|
|
@@ -61,6 +61,14 @@ export declare class ViewHandler {
|
|
|
61
61
|
getValidatedRules(tableRules?: TableRule, localParams?: LocalParams): ValidatedTableRules;
|
|
62
62
|
find(filter?: Filter, selectParams?: SelectParams, param3_unused?: undefined, tableRules?: TableRule, localParams?: LocalParams): Promise<any[]>;
|
|
63
63
|
findOne(filter?: Filter, selectParams?: SelectParams, param3_unused?: undefined, table_rules?: TableRule, localParams?: LocalParams): Promise<any>;
|
|
64
|
+
subscribe(filter: Filter, params: SubscribeParams, localFunc: (items: AnyObject[]) => any): Promise<{
|
|
65
|
+
unsubscribe: () => any;
|
|
66
|
+
}>;
|
|
67
|
+
subscribe(filter: Filter, params: SubscribeParams, localFunc?: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>;
|
|
68
|
+
subscribeOne(filter: Filter, params: SubscribeParams, localFunc: (item: AnyObject) => any): Promise<{
|
|
69
|
+
unsubscribe: () => any;
|
|
70
|
+
}>;
|
|
71
|
+
subscribeOne(filter: Filter, params: SubscribeParams, localFunc: (item: AnyObject) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>;
|
|
64
72
|
count(filter?: Filter, param2_unused?: undefined, param3_unused?: undefined, table_rules?: TableRule, localParams?: LocalParams): Promise<number>;
|
|
65
73
|
size(filter?: Filter, selectParams?: SelectParams, param3_unused?: undefined, table_rules?: TableRule, localParams?: LocalParams): Promise<string>;
|
|
66
74
|
getAllowedSelectFields(selectParams: FieldFilter, allowed_cols: FieldFilter, allow_empty?: boolean): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewHandler.d.ts","sourceRoot":"","sources":["ViewHandler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,SAAS,MAAM,YAAY,CAAC;AAExC,OAAO,EACL,UAAU,EAAE,WAAW,EAAE,YAAY,EACrC,OAAO,EAGP,SAAS,IAAI,KAAK,EAClB,SAAS,
|
|
1
|
+
{"version":3,"file":"ViewHandler.d.ts","sourceRoot":"","sources":["ViewHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -599,6 +599,133 @@ class ViewHandler {
|
|
|
599
599
|
throw (0, DboBuilder_1.parseError)(e, `Issue with dbo.${this.name}.findOne()`);
|
|
600
600
|
}
|
|
601
601
|
}
|
|
602
|
+
async subscribe(filter, params = {}, localFunc, table_rules, localParams) {
|
|
603
|
+
try {
|
|
604
|
+
if (this.is_view)
|
|
605
|
+
throw "Cannot subscribe to a view";
|
|
606
|
+
if (this.t)
|
|
607
|
+
throw "subscribe not allowed within transactions";
|
|
608
|
+
if (!localParams && !localFunc)
|
|
609
|
+
throw " missing data. provide -> localFunc | localParams { socket } ";
|
|
610
|
+
if (localParams && localParams.socket && localFunc) {
|
|
611
|
+
console.error({ localParams, localFunc });
|
|
612
|
+
throw " Cannot have localFunc AND socket ";
|
|
613
|
+
}
|
|
614
|
+
const { filterFields, forcedFilter } = table_rules?.select || {}, filterOpts = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }), condition = filterOpts.where, throttle = params?.throttle || 0, selectParams = (0, PubSubManager_1.omitKeys)(params || {}, ["throttle"]);
|
|
615
|
+
/** app_triggers condition field has an index which limits it's value */
|
|
616
|
+
const filterSize = JSON.stringify(filter || {}).length;
|
|
617
|
+
if (filterSize * 4 > 2704) {
|
|
618
|
+
throw "filter too big. Might exceed the btree version 4 maximum 2704. Use a primary key or a $rowhash filter instead";
|
|
619
|
+
}
|
|
620
|
+
if (!localFunc) {
|
|
621
|
+
if (!this.dboBuilder.prostgles.isSuperUser)
|
|
622
|
+
throw "Subscribe not possible. Must be superuser to add triggers 1856";
|
|
623
|
+
return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
|
|
624
|
+
.then(async (isValid) => {
|
|
625
|
+
let relatedTableSubscriptions = undefined;
|
|
626
|
+
if (this.is_view) {
|
|
627
|
+
const viewName = this.name;
|
|
628
|
+
const viewNameEscaped = this.escapedName;
|
|
629
|
+
/** Get list of used columns and their parent tables */
|
|
630
|
+
const { def } = await this.db.oneOrNone("SELECT pg_get_viewdef(${viewName}) as def", { viewName });
|
|
631
|
+
if (!def || typeof def !== "string")
|
|
632
|
+
(0, DboBuilder_1.makeErr)("Could get view definition");
|
|
633
|
+
const { fields } = await this.dboBuilder.dbo.sql(`SELECT * FROM ( \n ${def} \n ) prostgles_subscribe_view_definition LIMIT 0`, {});
|
|
634
|
+
const tableColumns = fields.filter(f => f.tableName && f.columnName);
|
|
635
|
+
/** Create exists filters for each table */
|
|
636
|
+
const tableIds = Array.from(new Set(tableColumns.map(tc => tc.tableID.toString())));
|
|
637
|
+
let relatedTableSubscriptions = tableIds.map(tableID => {
|
|
638
|
+
const table = this.dboBuilder.USER_TABLES?.find(t => t.relid === tableID);
|
|
639
|
+
let tableCols = tableColumns.filter(tc => tc.tableID.toString() === tableID);
|
|
640
|
+
/** If table has primary keys and they are all in this view then use only primary keys */
|
|
641
|
+
if (table?.pkey_columns?.every(pkey => tableCols.some(c => c.columnName === pkey))) {
|
|
642
|
+
tableCols = tableCols.filter(c => table?.pkey_columns?.includes(c.columnName));
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
/** Exclude non comparable data types */
|
|
646
|
+
tableCols = tableCols.filter(c => ["json", "xml"].includes(c.udt_name));
|
|
647
|
+
}
|
|
648
|
+
const { tableName, tableSchema } = tableCols[0];
|
|
649
|
+
const tableNameEscaped = [tableSchema, tableName].map(v => (0, prostgles_types_1.asName)(v)).join(".");
|
|
650
|
+
const relatedTableSubscription = {
|
|
651
|
+
tableName,
|
|
652
|
+
tableNameEscaped,
|
|
653
|
+
condition: `EXISTS (
|
|
654
|
+
SELECT 1
|
|
655
|
+
FROM ${viewNameEscaped}
|
|
656
|
+
WHERE ${tableCols.map(c => `${tableNameEscaped}.${JSON.stringify(c.columnName)} = ${viewNameEscaped}.${JSON.stringify(c.name)}`).join(" AND \n")}
|
|
657
|
+
AND ${condition || "TRUE"}
|
|
658
|
+
)`
|
|
659
|
+
};
|
|
660
|
+
return relatedTableSubscription;
|
|
661
|
+
});
|
|
662
|
+
/** Get list of remaining used inner tables */
|
|
663
|
+
const allUsedTables = await this.db.any("SELECT distinct table_name, table_schema FROM information_schema.view_column_usage WHERE view_name = ${viewName}", { viewName });
|
|
664
|
+
/** Remaining tables will have listeners on all records (condition = "TRUE") */
|
|
665
|
+
const remainingInnerTables = allUsedTables.filter(at => !tableColumns.some(dc => dc.tableName === at.table_name && dc.tableSchema === at.table_schema));
|
|
666
|
+
relatedTableSubscriptions = [
|
|
667
|
+
...relatedTableSubscriptions,
|
|
668
|
+
...remainingInnerTables.map(t => ({
|
|
669
|
+
tableName: t.table_name,
|
|
670
|
+
tableNameEscaped: [t.table_name, t.table_schema].map(v => JSON.stringify(v)).join("."),
|
|
671
|
+
condition: ""
|
|
672
|
+
}))
|
|
673
|
+
];
|
|
674
|
+
if (!relatedTableSubscriptions.length) {
|
|
675
|
+
throw "Could not subscribe to this view: no related tables found";
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
const { socket } = localParams ?? {};
|
|
679
|
+
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
680
|
+
return pubSubManager.addSub({
|
|
681
|
+
table_info: this.tableOrViewInfo,
|
|
682
|
+
socket,
|
|
683
|
+
table_rules,
|
|
684
|
+
table_name: this.name,
|
|
685
|
+
condition: condition,
|
|
686
|
+
relatedTableSubscriptions,
|
|
687
|
+
func: undefined,
|
|
688
|
+
filter: { ...filter },
|
|
689
|
+
params: { ...selectParams },
|
|
690
|
+
socket_id: socket?.id,
|
|
691
|
+
throttle,
|
|
692
|
+
last_throttled: 0,
|
|
693
|
+
}).then(channelName => ({ channelName }));
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
698
|
+
pubSubManager.addSub({
|
|
699
|
+
table_info: this.tableOrViewInfo,
|
|
700
|
+
socket: undefined,
|
|
701
|
+
table_rules,
|
|
702
|
+
condition,
|
|
703
|
+
func: localFunc,
|
|
704
|
+
filter: { ...filter },
|
|
705
|
+
params: { ...selectParams },
|
|
706
|
+
socket_id: undefined,
|
|
707
|
+
table_name: this.name,
|
|
708
|
+
throttle,
|
|
709
|
+
last_throttled: 0,
|
|
710
|
+
}).then(channelName => ({ channelName }));
|
|
711
|
+
const unsubscribe = async () => {
|
|
712
|
+
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
713
|
+
pubSubManager.removeLocalSub(this.name, condition, localFunc);
|
|
714
|
+
};
|
|
715
|
+
let res = Object.freeze({ unsubscribe });
|
|
716
|
+
return res;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
catch (e) {
|
|
720
|
+
if (localParams && localParams.testRule)
|
|
721
|
+
throw e;
|
|
722
|
+
throw (0, DboBuilder_1.parseError)(e, `dbo.${this.name}.subscribe()`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
subscribeOne(filter, params = {}, localFunc, table_rules, localParams) {
|
|
726
|
+
let func = localParams ? undefined : (rows) => localFunc(rows[0]);
|
|
727
|
+
return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
|
|
728
|
+
}
|
|
602
729
|
async count(filter, param2_unused, param3_unused, table_rules, localParams) {
|
|
603
730
|
filter = filter || {};
|
|
604
731
|
try {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
TableInfo as TInfo,
|
|
11
11
|
AnyObject,
|
|
12
12
|
isObject, isDefined, getKeys,
|
|
13
|
-
_PG_geometric, pickKeys
|
|
13
|
+
_PG_geometric, pickKeys, SubscribeParams
|
|
14
14
|
} from "prostgles-types";
|
|
15
15
|
import { DB, DBHandlerServer, Join } from "../Prostgles";
|
|
16
16
|
import {
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "../DboBuilder";
|
|
21
21
|
import { Graph } from "../shortestPath";
|
|
22
22
|
import { TableRule, UpdateRule, ValidateRow } from "../PublishParser";
|
|
23
|
-
import { asValue } from "../PubSubManager";
|
|
23
|
+
import { asValue, omitKeys } from "../PubSubManager";
|
|
24
24
|
import { TableHandler } from "./TableHandler";
|
|
25
25
|
import { asNameAlias, getNewQuery, parseFunctionObject, SelectItem, SelectItemValidated } from "./QueryBuilder/QueryBuilder";
|
|
26
26
|
import { COMPUTED_FIELDS, FieldSpec, FUNCTIONS, parseFunction, } from "./QueryBuilder/Functions";
|
|
@@ -718,6 +718,161 @@ export class ViewHandler {
|
|
|
718
718
|
}
|
|
719
719
|
}
|
|
720
720
|
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
async subscribe(filter: Filter, params: SubscribeParams, localFunc: (items: AnyObject[]) => any): Promise<{ unsubscribe: () => any }>
|
|
724
|
+
async subscribe(filter: Filter, params: SubscribeParams, localFunc?: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>
|
|
725
|
+
async subscribe(filter: Filter, params: SubscribeParams = {}, localFunc?: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams):
|
|
726
|
+
Promise<string | { unsubscribe: () => any }> {
|
|
727
|
+
try {
|
|
728
|
+
if (this.is_view) throw "Cannot subscribe to a view";
|
|
729
|
+
if (this.t) throw "subscribe not allowed within transactions";
|
|
730
|
+
if (!localParams && !localFunc) throw " missing data. provide -> localFunc | localParams { socket } ";
|
|
731
|
+
if (localParams && localParams.socket && localFunc) {
|
|
732
|
+
console.error({ localParams, localFunc })
|
|
733
|
+
throw " Cannot have localFunc AND socket ";
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const { filterFields, forcedFilter } = table_rules?.select || {},
|
|
737
|
+
filterOpts = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }),
|
|
738
|
+
condition = filterOpts.where,
|
|
739
|
+
throttle = params?.throttle || 0,
|
|
740
|
+
selectParams = omitKeys(params || {}, ["throttle"]);
|
|
741
|
+
|
|
742
|
+
/** app_triggers condition field has an index which limits it's value */
|
|
743
|
+
const filterSize = JSON.stringify(filter || {}).length;
|
|
744
|
+
if (filterSize * 4 > 2704) {
|
|
745
|
+
throw "filter too big. Might exceed the btree version 4 maximum 2704. Use a primary key or a $rowhash filter instead"
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if (!localFunc) {
|
|
749
|
+
if (!this.dboBuilder.prostgles.isSuperUser) throw "Subscribe not possible. Must be superuser to add triggers 1856";
|
|
750
|
+
return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
|
|
751
|
+
.then(async isValid => {
|
|
752
|
+
|
|
753
|
+
let relatedTableSubscriptions: {
|
|
754
|
+
tableName: string;
|
|
755
|
+
tableNameEscaped: string;
|
|
756
|
+
condition: string;
|
|
757
|
+
}[] | undefined = undefined;
|
|
758
|
+
|
|
759
|
+
if(this.is_view){
|
|
760
|
+
const viewName = this.name;
|
|
761
|
+
const viewNameEscaped = this.escapedName;
|
|
762
|
+
|
|
763
|
+
/** Get list of used columns and their parent tables */
|
|
764
|
+
const { def } = await this.db.oneOrNone("SELECT pg_get_viewdef(${viewName}) as def", { viewName });
|
|
765
|
+
if(!def || typeof def !== "string") makeErr("Could get view definition");
|
|
766
|
+
const { fields } = await this.dboBuilder.dbo.sql!(`SELECT * FROM ( \n ${def} \n ) prostgles_subscribe_view_definition LIMIT 0`, {});
|
|
767
|
+
const tableColumns = fields.filter(f => f.tableName && f.columnName);
|
|
768
|
+
|
|
769
|
+
/** Create exists filters for each table */
|
|
770
|
+
const tableIds = Array.from(new Set(tableColumns.map(tc => tc.tableID!.toString())));
|
|
771
|
+
let relatedTableSubscriptions = tableIds.map(tableID => {
|
|
772
|
+
const table = this.dboBuilder.USER_TABLES?.find(t => t.relid === tableID)!;
|
|
773
|
+
let tableCols = tableColumns.filter(tc => tc.tableID!.toString() === tableID);
|
|
774
|
+
|
|
775
|
+
/** If table has primary keys and they are all in this view then use only primary keys */
|
|
776
|
+
if(table?.pkey_columns?.every(pkey => tableCols.some(c => c.columnName === pkey))){
|
|
777
|
+
tableCols = tableCols.filter(c => table?.pkey_columns?.includes(c.columnName!))
|
|
778
|
+
} else {
|
|
779
|
+
/** Exclude non comparable data types */
|
|
780
|
+
tableCols = tableCols.filter(c => ["json", "xml"].includes(c.udt_name) )
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const { tableName, tableSchema } = tableCols[0]!;
|
|
784
|
+
const tableNameEscaped = [tableSchema!, tableName!].map(v => asName(v)).join(".");
|
|
785
|
+
|
|
786
|
+
const relatedTableSubscription = {
|
|
787
|
+
tableName,
|
|
788
|
+
tableNameEscaped,
|
|
789
|
+
condition: `EXISTS (
|
|
790
|
+
SELECT 1
|
|
791
|
+
FROM ${viewNameEscaped}
|
|
792
|
+
WHERE ${tableCols.map(c => `${tableNameEscaped}.${JSON.stringify(c.columnName)} = ${viewNameEscaped}.${JSON.stringify(c.name)}`).join(" AND \n")}
|
|
793
|
+
AND ${condition || "TRUE"}
|
|
794
|
+
)`
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
return relatedTableSubscription;
|
|
798
|
+
})
|
|
799
|
+
|
|
800
|
+
/** Get list of remaining used inner tables */
|
|
801
|
+
const allUsedTables: { table_name: string; table_schema: string; }[] = await this.db.any(
|
|
802
|
+
"SELECT distinct table_name, table_schema FROM information_schema.view_column_usage WHERE view_name = ${viewName}",
|
|
803
|
+
{ viewName }
|
|
804
|
+
);
|
|
805
|
+
|
|
806
|
+
/** Remaining tables will have listeners on all records (condition = "TRUE") */
|
|
807
|
+
const remainingInnerTables = allUsedTables.filter(at => !tableColumns.some(dc => dc.tableName === at.table_name && dc.tableSchema === at.table_schema));
|
|
808
|
+
relatedTableSubscriptions = [
|
|
809
|
+
...relatedTableSubscriptions,
|
|
810
|
+
...remainingInnerTables.map(t => ({
|
|
811
|
+
tableName: t.table_name,
|
|
812
|
+
tableNameEscaped: [t.table_name, t.table_schema].map(v => JSON.stringify(v)).join("."),
|
|
813
|
+
condition: ""
|
|
814
|
+
}))
|
|
815
|
+
];
|
|
816
|
+
|
|
817
|
+
if(!relatedTableSubscriptions.length){
|
|
818
|
+
throw "Could not subscribe to this view: no related tables found";
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
const { socket } = localParams ?? {};
|
|
823
|
+
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
824
|
+
return pubSubManager.addSub({
|
|
825
|
+
table_info: this.tableOrViewInfo,
|
|
826
|
+
socket,
|
|
827
|
+
table_rules,
|
|
828
|
+
table_name: this.name,
|
|
829
|
+
condition: condition,
|
|
830
|
+
relatedTableSubscriptions,
|
|
831
|
+
func: undefined,
|
|
832
|
+
filter: { ...filter },
|
|
833
|
+
params: { ...selectParams },
|
|
834
|
+
socket_id: socket?.id,
|
|
835
|
+
throttle,
|
|
836
|
+
last_throttled: 0,
|
|
837
|
+
}).then(channelName => ({ channelName }));
|
|
838
|
+
}) as string;
|
|
839
|
+
} else {
|
|
840
|
+
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
841
|
+
pubSubManager.addSub({
|
|
842
|
+
table_info: this.tableOrViewInfo,
|
|
843
|
+
socket: undefined,
|
|
844
|
+
table_rules,
|
|
845
|
+
condition,
|
|
846
|
+
func: localFunc,
|
|
847
|
+
filter: { ...filter },
|
|
848
|
+
params: { ...selectParams },
|
|
849
|
+
socket_id: undefined,
|
|
850
|
+
table_name: this.name,
|
|
851
|
+
throttle,
|
|
852
|
+
last_throttled: 0,
|
|
853
|
+
}).then(channelName => ({ channelName }));
|
|
854
|
+
const unsubscribe = async () => {
|
|
855
|
+
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
856
|
+
pubSubManager.removeLocalSub(this.name, condition, localFunc)
|
|
857
|
+
};
|
|
858
|
+
let res: { unsubscribe: () => any } = Object.freeze({ unsubscribe })
|
|
859
|
+
return res;
|
|
860
|
+
}
|
|
861
|
+
} catch (e) {
|
|
862
|
+
if (localParams && localParams.testRule) throw e;
|
|
863
|
+
throw parseError(e, `dbo.${this.name}.subscribe()`);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/* This should only be called from server */
|
|
868
|
+
subscribeOne(filter: Filter, params: SubscribeParams, localFunc: (item: AnyObject) => any): Promise<{ unsubscribe: () => any }>
|
|
869
|
+
subscribeOne(filter: Filter, params: SubscribeParams, localFunc: (item: AnyObject) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>
|
|
870
|
+
subscribeOne(filter: Filter, params: SubscribeParams = {}, localFunc: (item: AnyObject) => any, table_rules?: TableRule, localParams?: LocalParams):
|
|
871
|
+
Promise<string | { unsubscribe: () => any }> {
|
|
872
|
+
let func = localParams ? undefined : (rows: AnyObject[]) => localFunc(rows[0]);
|
|
873
|
+
return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
|
|
874
|
+
}
|
|
875
|
+
|
|
721
876
|
async count(filter?: Filter, param2_unused?: undefined, param3_unused?: undefined, table_rules?: TableRule, localParams?: LocalParams): Promise<number> {
|
|
722
877
|
filter = filter || {};
|
|
723
878
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runSQL.d.ts","sourceRoot":"","sources":["runSQL.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAE,WAAW,EAAyB,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK7C,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE,WAAW,CAAC,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"runSQL.d.ts","sourceRoot":"","sources":["runSQL.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAE,WAAW,EAAyB,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK7C,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE,WAAW,CAAC,EAAE,WAAW,gBAuHpI;AAED,eAAO,MAAM,SAAS,cAAqB,SAAS,gBAAgB,WAAW,KAAG,QAAQ,OAAO,CAOhG,CAAA;AAED,eAAO,MAAM,eAAe,cAAmB,QAAQ,OAAO,CAE7D,CAAA"}
|
package/lib/DboBuilder/runSQL.js
CHANGED
|
@@ -14,7 +14,25 @@ async function runSQL(query, params, options, localParams) {
|
|
|
14
14
|
}
|
|
15
15
|
/** Cache types */
|
|
16
16
|
this.DATA_TYPES ?? (this.DATA_TYPES = await this.db.any("SELECT oid, typname FROM pg_type") ?? []);
|
|
17
|
-
this.USER_TABLES ?? (this.USER_TABLES = await this.db.any(
|
|
17
|
+
this.USER_TABLES ?? (this.USER_TABLES = await this.db.any(`
|
|
18
|
+
SELECT relid, relname, schemaname, array_to_json(array_agg(c.column_name) FILTER (WHERE c.column_name IS NOT NULL))
|
|
19
|
+
FROM pg_catalog.pg_statio_user_tables t
|
|
20
|
+
LEFT JOIN (
|
|
21
|
+
SELECT a.attname as column_name, i.indrelid as table_oid
|
|
22
|
+
FROM pg_index i
|
|
23
|
+
JOIN pg_attribute a ON a.attrelid = i.indrelid
|
|
24
|
+
AND a.attnum = ANY(i.indkey)
|
|
25
|
+
WHERE i.indisprimary
|
|
26
|
+
) c
|
|
27
|
+
ON t.relid = c.table_oid
|
|
28
|
+
GROUP BY relid, relname, schemaname
|
|
29
|
+
`) ?? []);
|
|
30
|
+
this.USER_TABLE_COLUMNS ?? (this.USER_TABLE_COLUMNS = await this.db.any(`
|
|
31
|
+
SELECT t.relid, t.schemaname,t.relname, c.column_name, c.udt_name
|
|
32
|
+
FROM information_schema.columns c
|
|
33
|
+
INNER JOIN pg_catalog.pg_statio_user_tables t
|
|
34
|
+
ON c.table_schema = t.schemaname AND c.table_name = t.relname
|
|
35
|
+
`));
|
|
18
36
|
if (!(await (0, exports.canRunSQL)(this.prostgles, localParams)))
|
|
19
37
|
throw "Not allowed to run SQL";
|
|
20
38
|
const { returnType, allowListen, hasParams = true } = options || {};
|
|
@@ -80,13 +98,15 @@ async function runSQL(query, params, options, localParams) {
|
|
|
80
98
|
duration: 0,
|
|
81
99
|
..._qres,
|
|
82
100
|
fields: fields?.map(f => {
|
|
83
|
-
const dataType = this.DATA_TYPES.find(dt => +dt.oid === +f.dataTypeID)?.typname ?? "text",
|
|
101
|
+
const dataType = this.DATA_TYPES.find(dt => +dt.oid === +f.dataTypeID)?.typname ?? "text", table = this.USER_TABLES.find(t => +t.relid === +f.tableID), column = this.USER_TABLE_COLUMNS.find(c => +c.relid === +f.tableID && c.ordinal_position === f.columnID), tsDataType = (0, DboBuilder_1.postgresToTsType)(dataType);
|
|
84
102
|
return {
|
|
85
103
|
...f,
|
|
86
104
|
tsDataType,
|
|
87
105
|
dataType,
|
|
88
106
|
udt_name: dataType,
|
|
89
|
-
tableName:
|
|
107
|
+
tableName: table?.relname,
|
|
108
|
+
tableSchema: table?.schemaname,
|
|
109
|
+
columnName: column?.column_name
|
|
90
110
|
};
|
|
91
111
|
}) ?? []
|
|
92
112
|
};
|
package/lib/DboBuilder/runSQL.ts
CHANGED
|
@@ -17,7 +17,25 @@ export async function runSQL(this: DboBuilder, query: string, params: any, optio
|
|
|
17
17
|
|
|
18
18
|
/** Cache types */
|
|
19
19
|
this.DATA_TYPES ??= await this.db.any("SELECT oid, typname FROM pg_type") ?? [];
|
|
20
|
-
this.USER_TABLES ??= await this.db.any(
|
|
20
|
+
this.USER_TABLES ??= await this.db.any(`
|
|
21
|
+
SELECT relid, relname, schemaname, array_to_json(array_agg(c.column_name) FILTER (WHERE c.column_name IS NOT NULL))
|
|
22
|
+
FROM pg_catalog.pg_statio_user_tables t
|
|
23
|
+
LEFT JOIN (
|
|
24
|
+
SELECT a.attname as column_name, i.indrelid as table_oid
|
|
25
|
+
FROM pg_index i
|
|
26
|
+
JOIN pg_attribute a ON a.attrelid = i.indrelid
|
|
27
|
+
AND a.attnum = ANY(i.indkey)
|
|
28
|
+
WHERE i.indisprimary
|
|
29
|
+
) c
|
|
30
|
+
ON t.relid = c.table_oid
|
|
31
|
+
GROUP BY relid, relname, schemaname
|
|
32
|
+
`) ?? [];
|
|
33
|
+
this.USER_TABLE_COLUMNS ??= await this.db.any(`
|
|
34
|
+
SELECT t.relid, t.schemaname,t.relname, c.column_name, c.udt_name
|
|
35
|
+
FROM information_schema.columns c
|
|
36
|
+
INNER JOIN pg_catalog.pg_statio_user_tables t
|
|
37
|
+
ON c.table_schema = t.schemaname AND c.table_name = t.relname
|
|
38
|
+
`);
|
|
21
39
|
|
|
22
40
|
if (!(await canRunSQL(this.prostgles, localParams))) throw "Not allowed to run SQL";
|
|
23
41
|
|
|
@@ -87,7 +105,8 @@ export async function runSQL(this: DboBuilder, query: string, params: any, optio
|
|
|
87
105
|
..._qres,
|
|
88
106
|
fields: fields?.map(f => {
|
|
89
107
|
const dataType = this.DATA_TYPES!.find(dt => +dt.oid === +f.dataTypeID)?.typname ?? "text",
|
|
90
|
-
|
|
108
|
+
table = this.USER_TABLES!.find(t => +t.relid === +f.tableID),
|
|
109
|
+
column = this.USER_TABLE_COLUMNS!.find(c => +c.relid === +f.tableID && c.ordinal_position === f.columnID),
|
|
91
110
|
tsDataType = postgresToTsType(dataType);
|
|
92
111
|
|
|
93
112
|
return {
|
|
@@ -95,7 +114,9 @@ export async function runSQL(this: DboBuilder, query: string, params: any, optio
|
|
|
95
114
|
tsDataType,
|
|
96
115
|
dataType,
|
|
97
116
|
udt_name: dataType,
|
|
98
|
-
tableName:
|
|
117
|
+
tableName: table?.relname,
|
|
118
|
+
tableSchema: table?.schemaname,
|
|
119
|
+
columnName: column?.column_name
|
|
99
120
|
}
|
|
100
121
|
}) ?? []
|
|
101
122
|
};
|