prostgles-server 4.2.160 → 4.2.162
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/Auth/AuthHandler.d.ts +4 -4
- package/dist/Auth/AuthHandler.d.ts.map +1 -1
- package/dist/Auth/AuthHandler.js.map +1 -1
- package/dist/Auth/setEmailProvider.d.ts.map +1 -1
- package/dist/Auth/setEmailProvider.js +5 -5
- package/dist/Auth/setEmailProvider.js.map +1 -1
- package/dist/Auth/setupAuthRoutes.d.ts.map +1 -1
- package/dist/Auth/setupAuthRoutes.js +5 -6
- package/dist/Auth/setupAuthRoutes.js.map +1 -1
- package/lib/Auth/AuthHandler.ts +436 -0
- package/lib/Auth/AuthTypes.ts +280 -0
- package/lib/Auth/getSafeReturnURL.ts +35 -0
- package/lib/Auth/sendEmail.ts +83 -0
- package/lib/Auth/setAuthProviders.ts +128 -0
- package/lib/Auth/setEmailProvider.ts +85 -0
- package/lib/Auth/setupAuthRoutes.ts +159 -0
- package/lib/DBEventsManager.ts +178 -0
- package/lib/DBSchemaBuilder.ts +225 -0
- package/lib/DboBuilder/DboBuilder.ts +319 -0
- package/lib/DboBuilder/DboBuilderTypes.ts +361 -0
- package/lib/DboBuilder/QueryBuilder/Functions.ts +1153 -0
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +288 -0
- package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +263 -0
- package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +271 -0
- package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +136 -0
- package/lib/DboBuilder/QueryBuilder/prepareHaving.ts +22 -0
- package/lib/DboBuilder/QueryStreamer.ts +250 -0
- package/lib/DboBuilder/TableHandler/DataValidator.ts +428 -0
- package/lib/DboBuilder/TableHandler/TableHandler.ts +205 -0
- package/lib/DboBuilder/TableHandler/delete.ts +115 -0
- package/lib/DboBuilder/TableHandler/insert.ts +183 -0
- package/lib/DboBuilder/TableHandler/insertTest.ts +78 -0
- package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +62 -0
- package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +134 -0
- package/lib/DboBuilder/TableHandler/update.ts +126 -0
- package/lib/DboBuilder/TableHandler/updateBatch.ts +49 -0
- package/lib/DboBuilder/TableHandler/updateFile.ts +48 -0
- package/lib/DboBuilder/TableHandler/upsert.ts +34 -0
- package/lib/DboBuilder/ViewHandler/ViewHandler.ts +393 -0
- package/lib/DboBuilder/ViewHandler/count.ts +38 -0
- package/lib/DboBuilder/ViewHandler/find.ts +153 -0
- package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +73 -0
- package/lib/DboBuilder/ViewHandler/getExistsFilters.ts +74 -0
- package/lib/DboBuilder/ViewHandler/getInfo.ts +32 -0
- package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +84 -0
- package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +96 -0
- package/lib/DboBuilder/ViewHandler/parseFieldFilter.ts +105 -0
- package/lib/DboBuilder/ViewHandler/parseJoinPath.ts +208 -0
- package/lib/DboBuilder/ViewHandler/prepareSortItems.ts +163 -0
- package/lib/DboBuilder/ViewHandler/prepareWhere.ts +90 -0
- package/lib/DboBuilder/ViewHandler/size.ts +37 -0
- package/lib/DboBuilder/ViewHandler/subscribe.ts +118 -0
- package/lib/DboBuilder/ViewHandler/validateViewRules.ts +70 -0
- package/lib/DboBuilder/dboBuilderUtils.ts +222 -0
- package/lib/DboBuilder/getColumns.ts +114 -0
- package/lib/DboBuilder/getCondition.ts +201 -0
- package/lib/DboBuilder/getSubscribeRelatedTables.ts +190 -0
- package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +426 -0
- package/lib/DboBuilder/insertNestedRecords.ts +355 -0
- package/lib/DboBuilder/parseUpdateRules.ts +187 -0
- package/lib/DboBuilder/prepareShortestJoinPaths.ts +186 -0
- package/lib/DboBuilder/runSQL.ts +182 -0
- package/lib/DboBuilder/runTransaction.ts +50 -0
- package/lib/DboBuilder/sqlErrCodeToMsg.ts +254 -0
- package/lib/DboBuilder/uploadFile.ts +69 -0
- package/lib/Event_Trigger_Tags.ts +118 -0
- package/lib/FileManager/FileManager.ts +358 -0
- package/lib/FileManager/getValidatedFileType.ts +69 -0
- package/lib/FileManager/initFileManager.ts +187 -0
- package/lib/FileManager/upload.ts +62 -0
- package/lib/FileManager/uploadStream.ts +79 -0
- package/lib/Filtering.ts +463 -0
- package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +502 -0
- package/lib/JSONBValidation/validation.ts +143 -0
- package/lib/Logging.ts +127 -0
- package/lib/PostgresNotifListenManager.ts +143 -0
- package/lib/Prostgles.ts +485 -0
- package/lib/ProstglesTypes.ts +196 -0
- package/lib/PubSubManager/PubSubManager.ts +609 -0
- package/lib/PubSubManager/addSub.ts +138 -0
- package/lib/PubSubManager/addSync.ts +141 -0
- package/lib/PubSubManager/getCreatePubSubManagerError.ts +72 -0
- package/lib/PubSubManager/getPubSubManagerInitQuery.ts +662 -0
- package/lib/PubSubManager/initPubSubManager.ts +79 -0
- package/lib/PubSubManager/notifListener.ts +173 -0
- package/lib/PubSubManager/orphanTriggerCheck.ts +70 -0
- package/lib/PubSubManager/pushSubData.ts +55 -0
- package/lib/PublishParser/PublishParser.ts +162 -0
- package/lib/PublishParser/getFileTableRules.ts +124 -0
- package/lib/PublishParser/getSchemaFromPublish.ts +141 -0
- package/lib/PublishParser/getTableRulesWithoutFileTable.ts +177 -0
- package/lib/PublishParser/publishTypesAndUtils.ts +399 -0
- package/lib/RestApi.ts +127 -0
- package/lib/SchemaWatch/SchemaWatch.ts +90 -0
- package/lib/SchemaWatch/createSchemaWatchEventTrigger.ts +3 -0
- package/lib/SchemaWatch/getValidatedWatchSchemaType.ts +45 -0
- package/lib/SchemaWatch/getWatchSchemaTagList.ts +27 -0
- package/lib/SyncReplication.ts +557 -0
- package/lib/TableConfig/TableConfig.ts +468 -0
- package/lib/TableConfig/getColumnDefinitionQuery.ts +111 -0
- package/lib/TableConfig/getConstraintDefinitionQueries.ts +95 -0
- package/lib/TableConfig/getFutureTableSchema.ts +64 -0
- package/lib/TableConfig/getPGIndexes.ts +53 -0
- package/lib/TableConfig/getTableColumnQueries.ts +129 -0
- package/lib/TableConfig/initTableConfig.ts +326 -0
- package/lib/index.ts +13 -0
- package/lib/initProstgles.ts +319 -0
- package/lib/onSocketConnected.ts +102 -0
- package/lib/runClientRequest.ts +129 -0
- package/lib/shortestPath.ts +122 -0
- package/lib/typeTests/DBoGenerated.d.ts +320 -0
- package/lib/typeTests/dboTypeCheck.ts +81 -0
- package/lib/utils.ts +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Stefan L. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
PG_COLUMN_UDT_DATA_TYPE,
|
|
9
|
+
SQLOptions,
|
|
10
|
+
getJoinHandlers,
|
|
11
|
+
isDefined,
|
|
12
|
+
tryCatch
|
|
13
|
+
} from "prostgles-types";
|
|
14
|
+
import { getDBSchema } from "../DBSchemaBuilder";
|
|
15
|
+
import {
|
|
16
|
+
DB, Prostgles
|
|
17
|
+
} from "../Prostgles";
|
|
18
|
+
import { Join } from "../ProstglesTypes";
|
|
19
|
+
import { PubSubManager } from "../PubSubManager/PubSubManager";
|
|
20
|
+
import { getCreatePubSubManagerError } from "../PubSubManager/getCreatePubSubManagerError";
|
|
21
|
+
import {
|
|
22
|
+
DbTableInfo,
|
|
23
|
+
PublishParser
|
|
24
|
+
} from "../PublishParser/PublishParser";
|
|
25
|
+
import { Graph } from "../shortestPath";
|
|
26
|
+
import { clone } from "../utils";
|
|
27
|
+
import { DBHandlerServer, DbTxTableHandlers, LocalParams, TX, TableSchema, TxCB } from "./DboBuilderTypes";
|
|
28
|
+
import { QueryStreamer } from "./QueryStreamer";
|
|
29
|
+
import { TableHandler } from "./TableHandler/TableHandler";
|
|
30
|
+
import { JoinPaths, ViewHandler } from "./ViewHandler/ViewHandler";
|
|
31
|
+
import { parseJoinPath } from "./ViewHandler/parseJoinPath";
|
|
32
|
+
import { PGConstraint, getCanExecute, getConstraints, getErrorAsObject, getSerializedClientErrorFromPGError } from "./dboBuilderUtils";
|
|
33
|
+
import { getTablesForSchemaPostgresSQL } from "./getTablesForSchemaPostgresSQL";
|
|
34
|
+
import { prepareShortestJoinPaths } from "./prepareShortestJoinPaths";
|
|
35
|
+
import { cacheDBTypes, runSQL } from "./runSQL";
|
|
36
|
+
import { runClientTransactionStatement } from "./runTransaction";
|
|
37
|
+
|
|
38
|
+
export * from "./DboBuilderTypes";
|
|
39
|
+
export * from "./dboBuilderUtils";
|
|
40
|
+
|
|
41
|
+
type OidInfo = {
|
|
42
|
+
/**
|
|
43
|
+
* Oid
|
|
44
|
+
*/
|
|
45
|
+
relid: number;
|
|
46
|
+
relname: string;
|
|
47
|
+
schemaname: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type TableOidInfo = OidInfo & {
|
|
51
|
+
pkey_columns: string[] | null;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
type TableOidColumnInfo = OidInfo & {
|
|
55
|
+
column_name: string;
|
|
56
|
+
udt_name: string;
|
|
57
|
+
ordinal_position: number;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
export class DboBuilder {
|
|
62
|
+
tablesOrViews?: TableSchema[];
|
|
63
|
+
/**
|
|
64
|
+
* Used in obtaining column names for error messages
|
|
65
|
+
*/
|
|
66
|
+
constraints?: PGConstraint[];
|
|
67
|
+
|
|
68
|
+
db: DB;
|
|
69
|
+
|
|
70
|
+
dbo: DBHandlerServer;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Undefined if cannot create table triggers
|
|
74
|
+
*/
|
|
75
|
+
private _pubSubManager?: PubSubManager;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Used for db.sql field type details
|
|
79
|
+
*/
|
|
80
|
+
DATA_TYPES: { oid: string, typname: PG_COLUMN_UDT_DATA_TYPE }[] | undefined;
|
|
81
|
+
DATA_TYPES_DBKEY = "";
|
|
82
|
+
USER_TABLES: TableOidInfo[] | undefined;
|
|
83
|
+
USER_TABLE_COLUMNS: TableOidColumnInfo[] | undefined;
|
|
84
|
+
|
|
85
|
+
queryStreamer: QueryStreamer;
|
|
86
|
+
|
|
87
|
+
get tables(): DbTableInfo[] {
|
|
88
|
+
return (this.tablesOrViews ?? [])
|
|
89
|
+
.map(({ name, columns }) => {
|
|
90
|
+
const info = this.dbo[name]?.tableOrViewInfo;
|
|
91
|
+
if(!info) return undefined;
|
|
92
|
+
return {
|
|
93
|
+
name,
|
|
94
|
+
columns,
|
|
95
|
+
info
|
|
96
|
+
}})
|
|
97
|
+
.filter(isDefined);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getPubSubManager = async (): Promise<PubSubManager> => {
|
|
101
|
+
if (!this._pubSubManager) {
|
|
102
|
+
|
|
103
|
+
const canExecute = await getCanExecute(this.db)
|
|
104
|
+
if (!canExecute) throw "PubSubManager based subscriptions not possible: Cannot run EXECUTE statements on this connection";
|
|
105
|
+
|
|
106
|
+
const { pubSubManager, error, hasError } = await tryCatch(async () => {
|
|
107
|
+
const pubSubManager = await PubSubManager.create({
|
|
108
|
+
dboBuilder: this,
|
|
109
|
+
});
|
|
110
|
+
return { pubSubManager };
|
|
111
|
+
});
|
|
112
|
+
this._pubSubManager = pubSubManager;
|
|
113
|
+
if (hasError || !this._pubSubManager ) {
|
|
114
|
+
await this.prostgles.opts.onLog?.({
|
|
115
|
+
type: "debug",
|
|
116
|
+
command: "PubSubManager.create",
|
|
117
|
+
duration: 0,
|
|
118
|
+
error: getErrorAsObject(error)
|
|
119
|
+
});
|
|
120
|
+
throw "Could not create this._pubSubManager check logs";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return this._pubSubManager;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
tsTypesDefinition?: string;
|
|
128
|
+
joinGraph?: Graph;
|
|
129
|
+
private shortestJoinPaths: JoinPaths = [];
|
|
130
|
+
|
|
131
|
+
prostgles: Prostgles;
|
|
132
|
+
publishParser?: PublishParser;
|
|
133
|
+
|
|
134
|
+
onSchemaChange?: (event: { command: string; query: string }) => void;
|
|
135
|
+
|
|
136
|
+
private constructor(prostgles: Prostgles) {
|
|
137
|
+
this.prostgles = prostgles;
|
|
138
|
+
if (!this.prostgles.db) throw "db missing"
|
|
139
|
+
this.db = this.prostgles.db;
|
|
140
|
+
this.dbo = {} as unknown as DBHandlerServer;
|
|
141
|
+
this.queryStreamer = new QueryStreamer(this);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private init = async () => {
|
|
145
|
+
|
|
146
|
+
await this.build();
|
|
147
|
+
/* If watchSchema is enabled then PubSubManager must be created (if possible) because it creates the event trigger */
|
|
148
|
+
if (
|
|
149
|
+
this.prostgles.schemaWatch?.type.watchType === "DDL_trigger"
|
|
150
|
+
) {
|
|
151
|
+
await this.getPubSubManager()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public static create = async (prostgles: Prostgles): Promise<DboBuilder> => {
|
|
158
|
+
const res = new DboBuilder(prostgles)
|
|
159
|
+
return await res.init();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
destroy() {
|
|
164
|
+
this._pubSubManager?.destroy();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
_joins?: Join[];
|
|
168
|
+
get joins(): Join[] {
|
|
169
|
+
return clone(this._joins ?? []).filter(j => j.tables[0] !== j.tables[1]) as Join[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
set joins(j: Join[]) {
|
|
173
|
+
this._joins = clone(j);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getAllJoinPaths() {
|
|
177
|
+
return this.shortestJoinPaths;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
prepareShortestJoinPaths = async () => {
|
|
181
|
+
const { joins, shortestJoinPaths, joinGraph } = await prepareShortestJoinPaths(this);
|
|
182
|
+
this.joinGraph = joinGraph;
|
|
183
|
+
this.joins = joins;
|
|
184
|
+
this.shortestJoinPaths = shortestJoinPaths;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
runSQL = async (query: string, params: any, options: SQLOptions | undefined, localParams?: LocalParams) => {
|
|
188
|
+
return runSQL.bind(this)(query, params, options, localParams).catch(error => Promise.reject(getSerializedClientErrorFromPGError(error, { type: "sql" })));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
canSubscribe = false;
|
|
192
|
+
checkingCanSubscribe = false;
|
|
193
|
+
async build(): Promise<DBHandlerServer> {
|
|
194
|
+
if(!this.canSubscribe && !this.checkingCanSubscribe){
|
|
195
|
+
this.checkingCanSubscribe = true;
|
|
196
|
+
const subscribeError = await getCreatePubSubManagerError(this);
|
|
197
|
+
if(subscribeError){
|
|
198
|
+
console.error(
|
|
199
|
+
"Could not initiate PubSubManager. Realtime data/Subscriptions will not work. Error: ",
|
|
200
|
+
subscribeError
|
|
201
|
+
);
|
|
202
|
+
this.canSubscribe = false;
|
|
203
|
+
} else {
|
|
204
|
+
this.canSubscribe = true;
|
|
205
|
+
}
|
|
206
|
+
this.checkingCanSubscribe = false;
|
|
207
|
+
}
|
|
208
|
+
const start = Date.now();
|
|
209
|
+
const tablesOrViewsReq = await getTablesForSchemaPostgresSQL(this, this.prostgles.opts.schema);
|
|
210
|
+
await this.prostgles.opts.onLog?.({
|
|
211
|
+
type: "debug",
|
|
212
|
+
command: "DboBuilder.getTablesForSchemaPostgresSQL",
|
|
213
|
+
data: tablesOrViewsReq.durations,
|
|
214
|
+
duration: Date.now() - start,
|
|
215
|
+
})
|
|
216
|
+
this.tablesOrViews = tablesOrViewsReq.result;
|
|
217
|
+
|
|
218
|
+
this.constraints = await getConstraints(this.db, this.prostgles.opts.schema);
|
|
219
|
+
await this.prepareShortestJoinPaths();
|
|
220
|
+
|
|
221
|
+
this.dbo = {};
|
|
222
|
+
this.tablesOrViews.map(tov => {
|
|
223
|
+
const columnsForTypes = tov.columns.slice(0).sort((a, b) => a.name.localeCompare(b.name));
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
const filterKeywords = Object.values(this.prostgles.keywords);
|
|
227
|
+
const $filterCol = columnsForTypes.find(c => filterKeywords.includes(c.name));
|
|
228
|
+
if ($filterCol) {
|
|
229
|
+
throw `DboBuilder init error: \n\nTable ${JSON.stringify(tov.name)} column ${JSON.stringify($filterCol.name)} is colliding with Prostgles filtering functionality ($filter keyword)
|
|
230
|
+
Please provide a replacement keyword name using the $filter_keyName init option.
|
|
231
|
+
Alternatively you can rename the table column\n`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.dbo[tov.escaped_identifier] = new (tov.is_view ? ViewHandler : TableHandler)(this.db, tov, this, undefined, this.shortestJoinPaths);
|
|
235
|
+
|
|
236
|
+
if (this.shortestJoinPaths && this.shortestJoinPaths.find(jp => [jp.t1, jp.t2].includes(tov.name))) {
|
|
237
|
+
|
|
238
|
+
const table = tov.name;
|
|
239
|
+
|
|
240
|
+
this.dbo.innerJoin ??= {};
|
|
241
|
+
this.dbo.leftJoin ??= {};
|
|
242
|
+
this.dbo.innerJoinOne ??= {};
|
|
243
|
+
this.dbo.leftJoinOne ??= {};
|
|
244
|
+
|
|
245
|
+
const joinHandlers = getJoinHandlers(table);
|
|
246
|
+
//@ts-ignore
|
|
247
|
+
this.dbo.leftJoin[table] = joinHandlers.leftJoin;
|
|
248
|
+
this.dbo.innerJoin[table] = joinHandlers.innerJoin;
|
|
249
|
+
this.dbo.leftJoinOne[table] = joinHandlers.leftJoinOne;
|
|
250
|
+
this.dbo.innerJoinOne[table] = joinHandlers.innerJoinOne;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
if (this.prostgles.opts.transactions) {
|
|
255
|
+
let txKey = "tx";
|
|
256
|
+
if (typeof this.prostgles.opts.transactions === "string") txKey = this.prostgles.opts.transactions;
|
|
257
|
+
|
|
258
|
+
(this.dbo[txKey] as unknown as TX) = (cb: TxCB) => this.getTX(cb);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (!this.dbo.sql) {
|
|
262
|
+
|
|
263
|
+
this.dbo.sql = this.runSQL;
|
|
264
|
+
} else {
|
|
265
|
+
console.warn(`Could not create dbo.sql handler because there is already a table named "sql"`)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
this.tsTypesDefinition = [
|
|
269
|
+
`/* SCHEMA DEFINITON. Table names have been altered to work with Typescript */`,
|
|
270
|
+
`/* DBO Definition */`,
|
|
271
|
+
getDBSchema(this)
|
|
272
|
+
].join("\n");
|
|
273
|
+
|
|
274
|
+
return this.dbo;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
getShortestJoinPath = (viewHandler: ViewHandler, target: string): JoinPaths[number] | undefined => {
|
|
278
|
+
const source = viewHandler.name;
|
|
279
|
+
if(source === target){
|
|
280
|
+
const joinPath = parseJoinPath({
|
|
281
|
+
rawPath: target,
|
|
282
|
+
rootTable: source,
|
|
283
|
+
viewHandler
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
if(!joinPath) return undefined;
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
t1: source,
|
|
290
|
+
t2: target,
|
|
291
|
+
path: [source]
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const jp = this.shortestJoinPaths.find(jp => jp.t1 === source && jp.t2 === target);
|
|
296
|
+
return jp;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
getTX = async (cb: TxCB) => {
|
|
300
|
+
const transaction = await this.db.tx(t => {
|
|
301
|
+
const dbTX: DbTxTableHandlers & Pick<DBHandlerServer, "sql"> = {};
|
|
302
|
+
this.tablesOrViews?.map(tov => {
|
|
303
|
+
const handlerClass = tov.is_view ? ViewHandler : TableHandler;
|
|
304
|
+
dbTX[tov.name] = new handlerClass(this.db, tov, this, { t, dbTX }, this.shortestJoinPaths);
|
|
305
|
+
});
|
|
306
|
+
dbTX.sql = (q, args, opts, localP) => this.runSQL(q, args, opts, { tx: { dbTX, t }, ...(localP ?? {}) })
|
|
307
|
+
|
|
308
|
+
return cb(dbTX, t);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
return transaction;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
cacheDBTypes = cacheDBTypes.bind(this);
|
|
315
|
+
|
|
316
|
+
runClientTransactionStatement = (statement: string) => {
|
|
317
|
+
return runClientTransactionStatement(statement, this.prostgles.opts.dbConnection as any);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Stefan L. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
|
|
7
|
+
import * as pgPromise from 'pg-promise';
|
|
8
|
+
import {
|
|
9
|
+
AnyObject,
|
|
10
|
+
ColumnInfo,
|
|
11
|
+
DbJoinMaker,
|
|
12
|
+
EXISTS_KEY,
|
|
13
|
+
RawJoinPath,
|
|
14
|
+
SQLHandler,
|
|
15
|
+
TableInfo as TInfo,
|
|
16
|
+
UserLike
|
|
17
|
+
} from "prostgles-types";
|
|
18
|
+
import { BasicSession, ExpressReq } from "../Auth/AuthTypes";
|
|
19
|
+
import { BasicCallback } from "../PubSubManager/PubSubManager";
|
|
20
|
+
import {
|
|
21
|
+
PublishAllOrNothing
|
|
22
|
+
} from "../PublishParser/PublishParser";
|
|
23
|
+
import { FieldSpec, } from "./QueryBuilder/Functions";
|
|
24
|
+
import { TableHandler } from "./TableHandler/TableHandler";
|
|
25
|
+
import { ParsedJoinPath } from "./ViewHandler/parseJoinPath";
|
|
26
|
+
import pg = require('pg-promise/typescript/pg-subset');
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
type PGP = pgPromise.IMain<{}, pg.IClient>;
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
export type TableSchemaColumn = ColumnInfo & {
|
|
33
|
+
privileges: Partial<Record<"INSERT" | "REFERENCES" | "SELECT" | "UPDATE", true>>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type TableSchema = {
|
|
37
|
+
schema: string;
|
|
38
|
+
name: string;
|
|
39
|
+
escaped_identifier: string;
|
|
40
|
+
oid: number;
|
|
41
|
+
comment: string;
|
|
42
|
+
columns: TableSchemaColumn[];
|
|
43
|
+
is_view: boolean;
|
|
44
|
+
view_definition: string | null;
|
|
45
|
+
parent_tables: string[];
|
|
46
|
+
privileges: {
|
|
47
|
+
insert: boolean;
|
|
48
|
+
select: boolean;
|
|
49
|
+
update: boolean;
|
|
50
|
+
delete: boolean;
|
|
51
|
+
};
|
|
52
|
+
/** Cannot add triggers to hyperTables */
|
|
53
|
+
isHyperTable?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type SortItem = {
|
|
57
|
+
asc: boolean;
|
|
58
|
+
nulls?: "first" | "last";
|
|
59
|
+
nullEmpty?: boolean;
|
|
60
|
+
key: string;
|
|
61
|
+
nested?: {
|
|
62
|
+
table: string;
|
|
63
|
+
selectItemAlias: string;
|
|
64
|
+
isNumeric: boolean;
|
|
65
|
+
wrapperQuerySortItem: string;
|
|
66
|
+
joinAlias: string;
|
|
67
|
+
};
|
|
68
|
+
} & ({
|
|
69
|
+
type: "query";
|
|
70
|
+
fieldQuery: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: "position";
|
|
73
|
+
fieldPosition: number;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export type Media = {
|
|
77
|
+
id?: string;
|
|
78
|
+
title?: string;
|
|
79
|
+
extension?: string;
|
|
80
|
+
content_type?: string;
|
|
81
|
+
content_length?: number;
|
|
82
|
+
url?: string;
|
|
83
|
+
added?: Date;
|
|
84
|
+
signed_url?: string;
|
|
85
|
+
signed_url_expires?: number;
|
|
86
|
+
name?: string;
|
|
87
|
+
original_name?: string;
|
|
88
|
+
etag?: string;
|
|
89
|
+
deleted?: string | null;
|
|
90
|
+
deleted_from_storage?: string | null;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type ParsedMedia = Required<Pick<Media, "extension" | "content_type">>;
|
|
94
|
+
|
|
95
|
+
export type TxCB<TH = DbTxTableHandlers> = {
|
|
96
|
+
(t: TH & Pick<DBHandlerServer, "sql">, _t: pgPromise.ITask<{}>): (any | void);
|
|
97
|
+
}
|
|
98
|
+
export type TX<TH = TableHandlers> = {
|
|
99
|
+
(t: TxCB<TH>): Promise<(any | void)>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export type TableHandlers = {
|
|
103
|
+
[key: string]: Partial<TableHandler>;
|
|
104
|
+
}
|
|
105
|
+
export type DbTxTableHandlers = {
|
|
106
|
+
[key: string]: Omit<Partial<TableHandler>, "dbTx"> | Omit<TableHandler, "dbTx">;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
export type DBHandlerServerExtra<TH = TableHandlers, WithTransactions = true> = {
|
|
111
|
+
sql: SQLHandler;
|
|
112
|
+
} & (
|
|
113
|
+
WithTransactions extends true? { tx: TX<TH> } :
|
|
114
|
+
Record<string, never>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// export type DBHandlerServer<TH = TableHandlers> =
|
|
118
|
+
// TH &
|
|
119
|
+
// Partial<DbJoinMaker> & {
|
|
120
|
+
// sql?: SQLHandler
|
|
121
|
+
// } & {
|
|
122
|
+
// tx?: TX<TH>
|
|
123
|
+
// }
|
|
124
|
+
|
|
125
|
+
export type DBHandlerServer<TH = TableHandlers> =
|
|
126
|
+
TH &
|
|
127
|
+
Partial<DbJoinMaker> & {
|
|
128
|
+
sql?: SQLHandler
|
|
129
|
+
} & {
|
|
130
|
+
tx?: TX<TH>
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
export const pgp: PGP = pgPromise({
|
|
135
|
+
// ,query: function (e) { console.log({psql: e.query, params: e.params}); }
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export type TableInfo = TInfo & {
|
|
139
|
+
schema: string;
|
|
140
|
+
name: string;
|
|
141
|
+
oid: number;
|
|
142
|
+
comment: string;
|
|
143
|
+
columns: ColumnInfo[];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type ViewInfo = TableInfo & {
|
|
147
|
+
parent_tables: string[]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export type TableOrViewInfo = TableInfo & ViewInfo & {
|
|
151
|
+
is_view: boolean;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export type PRGLIOSocket = {
|
|
155
|
+
readonly id: string;
|
|
156
|
+
|
|
157
|
+
readonly handshake: {
|
|
158
|
+
query?: Record<string, string | string[] | undefined>;
|
|
159
|
+
/**
|
|
160
|
+
* IP Address
|
|
161
|
+
*/
|
|
162
|
+
address: string;
|
|
163
|
+
headers?: AnyObject & { cookie?: string; }; // e.g.: "some_arg=dwdaw; otherarg=23232"
|
|
164
|
+
auth?: Record<string, any>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
readonly on: (channel: string, params: any, cb?: (err: any, res?: any) => void) => any;// Promise<void>;
|
|
168
|
+
|
|
169
|
+
readonly emit: (channel: string, message?: any, cb?: BasicCallback) => any;
|
|
170
|
+
|
|
171
|
+
readonly once: (channel: string, cb: (_data: any, cb: BasicCallback) => void) => void;
|
|
172
|
+
|
|
173
|
+
readonly removeAllListeners: (channel: string) => void;
|
|
174
|
+
|
|
175
|
+
readonly disconnect: () => void;
|
|
176
|
+
|
|
177
|
+
readonly request: {
|
|
178
|
+
url?: string;
|
|
179
|
+
connection: { remoteAddress?: string; }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Used for session caching */
|
|
183
|
+
__prglCache?: {
|
|
184
|
+
session: BasicSession;
|
|
185
|
+
user: UserLike;
|
|
186
|
+
clientUser: UserLike;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_user?: AnyObject
|
|
190
|
+
|
|
191
|
+
/** Used for publish error caching */
|
|
192
|
+
prostgles?: AnyObject;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export type LocalParams = {
|
|
196
|
+
httpReq?: ExpressReq;
|
|
197
|
+
socket?: PRGLIOSocket;
|
|
198
|
+
func?: () => any;
|
|
199
|
+
isRemoteRequest?: {
|
|
200
|
+
user?: UserLike | undefined;
|
|
201
|
+
};
|
|
202
|
+
testRule?: boolean;
|
|
203
|
+
tableAlias?: string;
|
|
204
|
+
// subOne?: boolean;
|
|
205
|
+
|
|
206
|
+
tx?: {
|
|
207
|
+
dbTX: TableHandlers;
|
|
208
|
+
t: pgPromise.ITask<{}>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Used to exclude certain logs */
|
|
212
|
+
noLog?: boolean;
|
|
213
|
+
|
|
214
|
+
returnQuery?: boolean | "noRLS" | "where-condition";
|
|
215
|
+
returnNewQuery?: boolean;
|
|
216
|
+
/** Used for count/size queries */
|
|
217
|
+
bypassLimit?: boolean;
|
|
218
|
+
|
|
219
|
+
nestedInsert?: {
|
|
220
|
+
depth: number;
|
|
221
|
+
previousData: AnyObject;
|
|
222
|
+
previousTable: string;
|
|
223
|
+
referencingColumn?: string;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
export type Aggregation = {
|
|
229
|
+
field: string,
|
|
230
|
+
query: string,
|
|
231
|
+
alias: string,
|
|
232
|
+
getQuery: (alias: string) => string;
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export type Filter = AnyObject | { $and: Filter[] } | { $or: Filter[] };
|
|
236
|
+
|
|
237
|
+
export type JoinInfo = {
|
|
238
|
+
/**
|
|
239
|
+
* If true then all joins involve unique columns and the result is a 1 to 1 join
|
|
240
|
+
*/
|
|
241
|
+
expectOne?: boolean,
|
|
242
|
+
paths: {
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The table that JOIN ON columns refer to.
|
|
246
|
+
* columns in index = 1 refer to this table. index = 0 columns refer to previous JoinInfo.table
|
|
247
|
+
*/
|
|
248
|
+
table: string,
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Source and target JOIN ON column groups for each existing constraint
|
|
252
|
+
* Each inner array group will be combined with AND and outer arrays with OR to allow multiple references to the same table
|
|
253
|
+
* e.g.: [[source_table_column: string, table_column: string]]
|
|
254
|
+
*/
|
|
255
|
+
on: [string, string][][],
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Source table name
|
|
259
|
+
*/
|
|
260
|
+
source: string,
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Target table name
|
|
264
|
+
*/
|
|
265
|
+
target: string
|
|
266
|
+
}[]
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
export type CommonTableRules = {
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* True by default. Allows clients to get column information on any columns that are allowed in (select, insert, update) field rules.
|
|
274
|
+
*/
|
|
275
|
+
getColumns?: PublishAllOrNothing;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* True by default. Allows clients to get table information (oid, comment, label, has_media).
|
|
279
|
+
*/
|
|
280
|
+
getInfo?: PublishAllOrNothing
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export type ValidatedTableRules = CommonTableRules & {
|
|
284
|
+
|
|
285
|
+
/* All columns of the view/table. Includes computed fields as well */
|
|
286
|
+
allColumns: FieldSpec[];
|
|
287
|
+
|
|
288
|
+
select: {
|
|
289
|
+
/* Fields you can select */
|
|
290
|
+
fields: string[];
|
|
291
|
+
|
|
292
|
+
/* Fields you can select */
|
|
293
|
+
orderByFields: string[];
|
|
294
|
+
|
|
295
|
+
/* Filter applied to every select */
|
|
296
|
+
filterFields: string[];
|
|
297
|
+
|
|
298
|
+
/* Filter applied to every select */
|
|
299
|
+
forcedFilter: any;
|
|
300
|
+
|
|
301
|
+
/* Max limit allowed for each select. 1000 by default. If null then an unlimited select is allowed when providing { limit: null } */
|
|
302
|
+
maxLimit: number | null;
|
|
303
|
+
},
|
|
304
|
+
update: {
|
|
305
|
+
/* Fields you can update */
|
|
306
|
+
fields: string[];
|
|
307
|
+
|
|
308
|
+
/* Fields you can return after updating */
|
|
309
|
+
returningFields: string[];
|
|
310
|
+
|
|
311
|
+
/* Fields you can use in filtering when updating */
|
|
312
|
+
filterFields: string[];
|
|
313
|
+
|
|
314
|
+
/* Filter applied to every update. Filter fields cannot be updated */
|
|
315
|
+
forcedFilter: any;
|
|
316
|
+
|
|
317
|
+
/* Data applied to every update */
|
|
318
|
+
forcedData: any;
|
|
319
|
+
},
|
|
320
|
+
insert: {
|
|
321
|
+
/* Fields you can insert */
|
|
322
|
+
fields: string[];
|
|
323
|
+
|
|
324
|
+
/* Fields you can return after inserting. Will return select.fields by default */
|
|
325
|
+
returningFields: string[];
|
|
326
|
+
|
|
327
|
+
/* Data applied to every insert */
|
|
328
|
+
forcedData: any;
|
|
329
|
+
},
|
|
330
|
+
delete: {
|
|
331
|
+
/* Fields to filter by when deleting */
|
|
332
|
+
filterFields: string[];
|
|
333
|
+
|
|
334
|
+
/* Filter applied to every deletes */
|
|
335
|
+
forcedFilter: any;
|
|
336
|
+
|
|
337
|
+
/* Fields you can return after deleting */
|
|
338
|
+
returningFields: string[];
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export type ExistsFilterConfig = {
|
|
343
|
+
existType: EXISTS_KEY;
|
|
344
|
+
/**
|
|
345
|
+
* Target table filter. target table is the last table from tables
|
|
346
|
+
*/
|
|
347
|
+
targetTableFilter: Filter;
|
|
348
|
+
|
|
349
|
+
} & ({
|
|
350
|
+
isJoined: true;
|
|
351
|
+
/**
|
|
352
|
+
* list of join tables in their order
|
|
353
|
+
* If table path starts with "**" then get shortest join to first table
|
|
354
|
+
* e.g.: "**.users" means finding the shortest join from root table to users table
|
|
355
|
+
*/
|
|
356
|
+
path: RawJoinPath;
|
|
357
|
+
parsedPath: ParsedJoinPath[]
|
|
358
|
+
} | {
|
|
359
|
+
isJoined: false;
|
|
360
|
+
targetTable: string;
|
|
361
|
+
});
|