prostgles-server 4.2.605 → 4.2.607
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/Audit/AuditTable.d.ts +18 -0
- package/dist/Audit/AuditTable.d.ts.map +1 -0
- package/dist/Audit/AuditTable.js +18 -0
- package/dist/Audit/AuditTable.js.map +1 -0
- package/dist/Audit/AuditTypes.d.ts +25 -0
- package/dist/Audit/AuditTypes.d.ts.map +1 -0
- package/dist/Audit/AuditTypes.js +3 -0
- package/dist/Audit/AuditTypes.js.map +1 -0
- package/dist/Audit/getAuditTableConfig.d.ts +13 -0
- package/dist/Audit/getAuditTableConfig.d.ts.map +1 -0
- package/dist/Audit/getAuditTableConfig.js +54 -0
- package/dist/Audit/getAuditTableConfig.js.map +1 -0
- package/dist/Audit/parseAuditConfig.d.ts +5 -0
- package/dist/Audit/parseAuditConfig.d.ts.map +1 -0
- package/dist/Audit/parseAuditConfig.js +123 -0
- package/dist/Audit/parseAuditConfig.js.map +1 -0
- package/dist/DboBuilder/DboBuilder.js +2 -2
- package/dist/DboBuilder/DboBuilder.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +1 -1
- package/dist/DboBuilder/ViewHandler/getInfo.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/getInfo.js +5 -46
- package/dist/DboBuilder/ViewHandler/getInfo.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/getRawInfo.d.ts +7 -0
- package/dist/DboBuilder/ViewHandler/getRawInfo.d.ts.map +1 -0
- package/dist/DboBuilder/ViewHandler/getRawInfo.js +51 -0
- package/dist/DboBuilder/ViewHandler/getRawInfo.js.map +1 -0
- package/dist/DboBuilder/getColumns.d.ts +5 -0
- package/dist/DboBuilder/getColumns.d.ts.map +1 -1
- package/dist/DboBuilder/getColumns.js +80 -74
- package/dist/DboBuilder/getColumns.js.map +1 -1
- package/dist/DboBuilder/runSql/QueryStreamer.d.ts.map +1 -1
- package/dist/DboBuilder/runSql/QueryStreamer.js +1 -0
- package/dist/DboBuilder/runSql/QueryStreamer.js.map +1 -1
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts +3 -3
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js +2 -2
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.js.map +1 -1
- package/dist/DboBuilder/schema/getViewReferenceColumns.d.ts +2 -2
- package/dist/DboBuilder/schema/getViewReferenceColumns.d.ts.map +1 -1
- package/dist/DboBuilder/schema/getViewReferenceColumns.js +4 -2
- package/dist/DboBuilder/schema/getViewReferenceColumns.js.map +1 -1
- package/dist/Prostgles.d.ts +6 -0
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +33 -5
- package/dist/Prostgles.js.map +1 -1
- package/dist/ProstglesTypes.d.ts +3 -0
- package/dist/ProstglesTypes.d.ts.map +1 -1
- package/dist/ProstglesTypes.js.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +1 -1
- package/dist/PubSubManager/getCreatePubSubManagerError.js +1 -1
- package/dist/PubSubManager/getCreatePubSubManagerError.js.map +1 -1
- package/dist/PubSubManager/init/getPubSubManagerInitQuery.js +4 -4
- package/dist/PubSubManager/init/getPubSubManagerInitQuery.js.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.js +5 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +1 -1
- package/dist/TableConfig/TableConfigTypes.d.ts +1 -1
- package/dist/TableConfig/TableConfigTypes.d.ts.map +1 -1
- package/dist/TableConfig/TableConfigurator.js +3 -3
- package/dist/TableConfig/TableConfigurator.js.map +1 -1
- package/dist/TableConfig/getTableConfigSchemaQueries.d.ts.map +1 -1
- package/dist/TableConfig/getTableConfigSchemaQueries.js +3 -2
- package/dist/TableConfig/getTableConfigSchemaQueries.js.map +1 -1
- package/dist/TableConfig/getTableTriggerQueries.d.ts +2 -2
- package/dist/TableConfig/getTableTriggerQueries.d.ts.map +1 -1
- package/dist/TableConfig/getTableTriggerQueries.js +57 -34
- package/dist/TableConfig/getTableTriggerQueries.js.map +1 -1
- package/dist/TableConfig/initTableConfig.d.ts.map +1 -1
- package/dist/TableConfig/initTableConfig.js +5 -6
- package/dist/TableConfig/initTableConfig.js.map +1 -1
- package/dist/TableConfig/managedTriggerNames.d.ts +8 -0
- package/dist/TableConfig/managedTriggerNames.d.ts.map +1 -0
- package/dist/TableConfig/managedTriggerNames.js +17 -0
- package/dist/TableConfig/managedTriggerNames.js.map +1 -0
- package/dist/TableConfig/runSQLFile.js +1 -1
- package/dist/TableConfig/runSQLFile.js.map +1 -1
- package/dist/TableConfig/syncTableTriggers.d.ts +4 -0
- package/dist/TableConfig/syncTableTriggers.d.ts.map +1 -0
- package/dist/TableConfig/syncTableTriggers.js +32 -0
- package/dist/TableConfig/syncTableTriggers.js.map +1 -0
- package/dist/deferDbQueries.d.ts +4 -0
- package/dist/deferDbQueries.d.ts.map +1 -0
- package/dist/deferDbQueries.js +24 -0
- package/dist/deferDbQueries.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/initProstgles.d.ts +1 -1
- package/dist/initProstgles.d.ts.map +1 -1
- package/dist/initProstgles.js +24 -13
- package/dist/initProstgles.js.map +1 -1
- package/dist/updateConfiguration.d.ts.map +1 -1
- package/dist/updateConfiguration.js +1 -6
- package/dist/updateConfiguration.js.map +1 -1
- package/lib/Audit/AuditTable.ts +25 -0
- package/lib/Audit/AuditTypes.ts +35 -0
- package/lib/Audit/getAuditTableConfig.ts +76 -0
- package/lib/Audit/parseAuditConfig.ts +158 -0
- package/lib/DboBuilder/DboBuilder.ts +2 -2
- package/lib/DboBuilder/ViewHandler/getInfo.ts +5 -58
- package/lib/DboBuilder/ViewHandler/getRawInfo.ts +65 -0
- package/lib/DboBuilder/getColumns.ts +105 -92
- package/lib/DboBuilder/runSql/QueryStreamer.ts +1 -0
- package/lib/DboBuilder/schema/getTablesForSchemaPostgresSQL.ts +2 -2
- package/lib/DboBuilder/schema/getViewReferenceColumns.ts +7 -8
- package/lib/Prostgles.ts +34 -5
- package/lib/ProstglesTypes.ts +3 -0
- package/lib/PubSubManager/getCreatePubSubManagerError.ts +1 -1
- package/lib/PubSubManager/init/getPubSubManagerInitQuery.ts +4 -4
- package/lib/PublishParser/getTableRulesWithoutFileTable.ts +6 -1
- package/lib/TableConfig/TableConfigTypes.ts +1 -1
- package/lib/TableConfig/TableConfigurator.ts +2 -2
- package/lib/TableConfig/getTableConfigSchemaQueries.ts +3 -2
- package/lib/TableConfig/getTableTriggerQueries.ts +85 -41
- package/lib/TableConfig/initTableConfig.ts +4 -7
- package/lib/TableConfig/managedTriggerNames.ts +16 -0
- package/lib/TableConfig/runSQLFile.ts +1 -1
- package/lib/TableConfig/syncTableTriggers.ts +42 -0
- package/lib/deferDbQueries.ts +27 -0
- package/lib/index.ts +3 -0
- package/lib/initProstgles.ts +24 -12
- package/lib/updateConfiguration.ts +1 -6
- package/package.json +1 -1
- package/dist/TableConfig/getTableTriggerQueries.spec.d.ts +0 -2
- package/dist/TableConfig/getTableTriggerQueries.spec.d.ts.map +0 -1
- package/dist/TableConfig/getTableTriggerQueries.spec.js +0 -56
- package/dist/TableConfig/getTableTriggerQueries.spec.js.map +0 -1
- package/lib/TableConfig/getTableTriggerQueries.spec.ts +0 -77
|
@@ -250,7 +250,7 @@ export class DboBuilder {
|
|
|
250
250
|
this.checkingCanSubscribe = false;
|
|
251
251
|
}
|
|
252
252
|
const start = Date.now();
|
|
253
|
-
const tablesOrViewsReq = await getTablesForSchemaPostgresSQL(this, {
|
|
253
|
+
const tablesOrViewsReq = await getTablesForSchemaPostgresSQL({ db: this.prostgles.dbForSchema! }, {
|
|
254
254
|
schemaFilter: this.prostgles.opts.schemaFilter,
|
|
255
255
|
});
|
|
256
256
|
await this.prostgles.opts.onLog?.({
|
|
@@ -262,7 +262,7 @@ export class DboBuilder {
|
|
|
262
262
|
const tablesOrViews = tablesOrViewsReq.result;
|
|
263
263
|
this.tablesOrViews = tablesOrViews;
|
|
264
264
|
|
|
265
|
-
this.constraints = await getConstraints(this.
|
|
265
|
+
this.constraints = await getConstraints(this.prostgles.dbForSchema!, this.prostgles.opts.schemaFilter);
|
|
266
266
|
await this.prepareShortestJoinPaths();
|
|
267
267
|
|
|
268
268
|
this.dbo = {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type TableInfo as TInfo } from "prostgles-types/dist";
|
|
2
2
|
import type { ParsedTableRule } from "../../PublishParser/PublishParser";
|
|
3
3
|
import type { LocalParams } from "../DboBuilder";
|
|
4
|
+
import { getRawInfo } from "./getRawInfo";
|
|
5
|
+
import { getRawColumns } from "../getColumns";
|
|
4
6
|
import type { ViewHandler } from "./ViewHandler";
|
|
5
7
|
|
|
6
8
|
export async function getInfo(
|
|
@@ -11,80 +13,25 @@ export async function getInfo(
|
|
|
11
13
|
tableRules?: ParsedTableRule,
|
|
12
14
|
localParams?: LocalParams,
|
|
13
15
|
): Promise<TInfo> {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const fileTableName = this.dboBuilder.prostgles.opts.fileTable?.tableName;
|
|
17
|
-
|
|
16
|
+
const tableInfo = getRawInfo.call(this, lang, tableRules, localParams);
|
|
18
17
|
await this._log({
|
|
19
18
|
command: "getInfo",
|
|
20
19
|
localParams,
|
|
21
20
|
data: { lang },
|
|
22
21
|
duration: 0,
|
|
23
22
|
});
|
|
24
|
-
const allowedFieldsToSelect = this.parseFieldFilter(tableRules?.select?.fields);
|
|
25
|
-
const { requiredNestedInserts, allowedNestedInserts } = tableRules?.insert ?? {};
|
|
26
|
-
const label = this.dboBuilder.prostgles.tableConfigurator?.getTableLabel({
|
|
27
|
-
tableName: this.name,
|
|
28
|
-
lang,
|
|
29
|
-
});
|
|
30
|
-
const tableInfo: TInfo = {
|
|
31
|
-
oid: this.tableOrViewInfo.oid,
|
|
32
|
-
comment: this.tableOrViewInfo.comment,
|
|
33
|
-
qualifiedNameParts: this.tableOrViewInfo.qualifiedNameParts,
|
|
34
|
-
label,
|
|
35
|
-
isFileTable:
|
|
36
|
-
!this.is_media ? undefined : (
|
|
37
|
-
{
|
|
38
|
-
allowedNestedInserts,
|
|
39
|
-
}
|
|
40
|
-
),
|
|
41
|
-
isView: this.isView,
|
|
42
|
-
hasFiles: Boolean(
|
|
43
|
-
!this.is_media &&
|
|
44
|
-
fileTableName &&
|
|
45
|
-
this.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName)),
|
|
46
|
-
),
|
|
47
|
-
fileTableName,
|
|
48
|
-
dynamicRules: {
|
|
49
|
-
update: Boolean(tableRules?.update?.dynamicFields?.length),
|
|
50
|
-
},
|
|
51
|
-
/**
|
|
52
|
-
* Only show column groups that are fully allowed to be selected by the user
|
|
53
|
-
*/
|
|
54
|
-
uniqueColumnGroups: this.tableOrViewInfo.uniqueColumnGroups?.filter(
|
|
55
|
-
(g) => !localParams || g.every((c) => allowedFieldsToSelect.includes(c)),
|
|
56
|
-
),
|
|
57
|
-
publishInfo: {
|
|
58
|
-
select: validatedTableRules.select && {
|
|
59
|
-
disabledMethods: validatedTableRules.select.disableMethods,
|
|
60
|
-
syncConfig: this.dboBuilder.prostgles.tableConfigurator?.getTableSyncConfig(this.name),
|
|
61
|
-
},
|
|
62
|
-
insert: validatedTableRules.insert && {
|
|
63
|
-
requiredNestedInserts,
|
|
64
|
-
allowedNestedInserts: allowedNestedInserts?.map((t) => t.table),
|
|
65
|
-
},
|
|
66
|
-
update: validatedTableRules.update && {
|
|
67
|
-
disabledMethods: tableRules?.update?.disableMethods,
|
|
68
|
-
},
|
|
69
|
-
delete: validatedTableRules.delete && {},
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
|
|
73
23
|
const modifyClientSchema = this.dboBuilder.prostgles.opts.modifyClientSchema;
|
|
74
|
-
if (!modifyClientSchema)
|
|
75
|
-
return tableInfo;
|
|
76
|
-
}
|
|
24
|
+
if (!modifyClientSchema) return tableInfo;
|
|
77
25
|
|
|
78
26
|
const modifiedTableSchema = await modifyClientSchema(
|
|
79
27
|
{
|
|
80
28
|
name: this.name,
|
|
81
29
|
...tableInfo,
|
|
82
|
-
columns:
|
|
30
|
+
columns: await getRawColumns.call(this, lang, undefined, tableRules, localParams),
|
|
83
31
|
},
|
|
84
32
|
this.config,
|
|
85
33
|
localParams?.isRemoteRequest?.clientInfo,
|
|
86
34
|
);
|
|
87
|
-
|
|
88
35
|
const { columns, name, ...rest } = modifiedTableSchema;
|
|
89
36
|
return rest;
|
|
90
37
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type TableInfo as TInfo } from "prostgles-types/dist";
|
|
2
|
+
import type { ParsedTableRule } from "../../PublishParser/PublishParser";
|
|
3
|
+
import type { LocalParams } from "../DboBuilder";
|
|
4
|
+
import type { ViewHandler } from "./ViewHandler";
|
|
5
|
+
|
|
6
|
+
/** Table metadata before client schema customisation. */
|
|
7
|
+
export function getRawInfo(
|
|
8
|
+
this: ViewHandler,
|
|
9
|
+
lang?: string,
|
|
10
|
+
tableRules?: ParsedTableRule,
|
|
11
|
+
localParams?: LocalParams,
|
|
12
|
+
): TInfo {
|
|
13
|
+
const validatedTableRules = this.getValidatedRules(tableRules, localParams);
|
|
14
|
+
const fileTableName = this.dboBuilder.prostgles.opts.fileTable?.tableName;
|
|
15
|
+
const allowedFieldsToSelect = this.parseFieldFilter(tableRules?.select?.fields);
|
|
16
|
+
const { requiredNestedInserts, allowedNestedInserts } = tableRules?.insert ?? {};
|
|
17
|
+
const label = this.dboBuilder.prostgles.tableConfigurator?.getTableLabel({
|
|
18
|
+
tableName: this.name,
|
|
19
|
+
lang,
|
|
20
|
+
});
|
|
21
|
+
const tableInfo: TInfo = {
|
|
22
|
+
oid: this.tableOrViewInfo.oid,
|
|
23
|
+
comment: this.tableOrViewInfo.comment,
|
|
24
|
+
qualifiedNameParts: this.tableOrViewInfo.qualifiedNameParts,
|
|
25
|
+
label,
|
|
26
|
+
isFileTable:
|
|
27
|
+
!this.is_media ? undefined : (
|
|
28
|
+
{
|
|
29
|
+
allowedNestedInserts,
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
isView: this.isView,
|
|
33
|
+
hasFiles: Boolean(
|
|
34
|
+
!this.is_media &&
|
|
35
|
+
fileTableName &&
|
|
36
|
+
this.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName)),
|
|
37
|
+
),
|
|
38
|
+
fileTableName,
|
|
39
|
+
dynamicRules: {
|
|
40
|
+
update: Boolean(tableRules?.update?.dynamicFields?.length),
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* Only show column groups that are fully allowed to be selected by the user
|
|
44
|
+
*/
|
|
45
|
+
uniqueColumnGroups: this.tableOrViewInfo.uniqueColumnGroups?.filter(
|
|
46
|
+
(g) => !localParams || g.every((c) => allowedFieldsToSelect.includes(c)),
|
|
47
|
+
),
|
|
48
|
+
publishInfo: {
|
|
49
|
+
select: validatedTableRules.select && {
|
|
50
|
+
disabledMethods: validatedTableRules.select.disableMethods,
|
|
51
|
+
syncConfig: this.dboBuilder.prostgles.tableConfigurator?.getTableSyncConfig(this.name),
|
|
52
|
+
},
|
|
53
|
+
insert: validatedTableRules.insert && {
|
|
54
|
+
requiredNestedInserts,
|
|
55
|
+
allowedNestedInserts: allowedNestedInserts?.map((t) => t.table),
|
|
56
|
+
},
|
|
57
|
+
update: validatedTableRules.update && {
|
|
58
|
+
disabledMethods: tableRules?.update?.disableMethods,
|
|
59
|
+
},
|
|
60
|
+
delete: validatedTableRules.delete && {},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return tableInfo;
|
|
65
|
+
}
|
|
@@ -5,6 +5,7 @@ import type { LocalParams } from "./DboBuilder";
|
|
|
5
5
|
import { getErrorAsObject, getSerializedClientErrorFromPGError } from "./DboBuilder";
|
|
6
6
|
import type { TableHandler } from "./TableHandler/TableHandler";
|
|
7
7
|
import type { ViewHandler } from "./ViewHandler/ViewHandler";
|
|
8
|
+
import { getRawInfo } from "./ViewHandler/getRawInfo";
|
|
8
9
|
|
|
9
10
|
export const isTableHandler = (v: any): v is TableHandler => "parseUpdateRules" in v;
|
|
10
11
|
|
|
@@ -18,102 +19,12 @@ export async function getColumns(
|
|
|
18
19
|
): Promise<ValidatedColumnInfo[]> {
|
|
19
20
|
const start = Date.now();
|
|
20
21
|
try {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
let dynamicUpdateFields = this.column_names;
|
|
24
|
-
|
|
25
|
-
if (params && tableRules && isTableHandler(this)) {
|
|
26
|
-
if (
|
|
27
|
-
!isObject(params) ||
|
|
28
|
-
!isObject(params.filter) ||
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
30
|
-
params.rule !== "update"
|
|
31
|
-
) {
|
|
32
|
-
throw (
|
|
33
|
-
"params must be { rule: 'update', filter: object } but received: " +
|
|
34
|
-
JSON.stringify(params)
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!tableRules.update) {
|
|
39
|
-
dynamicUpdateFields = [];
|
|
40
|
-
} else {
|
|
41
|
-
const { filter } = params;
|
|
42
|
-
const updateRules = await this.parseUpdateRules(filter, undefined, tableRules, localParams);
|
|
43
|
-
dynamicUpdateFields = updateRules.fields;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const rawColumns: ValidatedColumnInfo[] = this.columns
|
|
48
|
-
.filter((c) => {
|
|
49
|
-
const { insert, select, update } = rules;
|
|
50
|
-
|
|
51
|
-
return [insert, select, update]
|
|
52
|
-
.filter(isDefined)
|
|
53
|
-
.flatMap((rule) => rule.fields)
|
|
54
|
-
.includes(c.name);
|
|
55
|
-
})
|
|
56
|
-
.map((_c) => {
|
|
57
|
-
const c = { ..._c };
|
|
58
|
-
|
|
59
|
-
const label = capitalizeFirstLetter(c.name, " ");
|
|
60
|
-
|
|
61
|
-
const select = !!c.privileges.SELECT;
|
|
62
|
-
const insert = !!c.privileges.INSERT;
|
|
63
|
-
const _delete = !!this.tableOrViewInfo.privileges.delete;
|
|
64
|
-
let update = !!c.privileges.UPDATE;
|
|
65
|
-
|
|
66
|
-
const prostgles = this.dboBuilder.prostgles;
|
|
67
|
-
const fileConfig = getFileColumnInfo({
|
|
68
|
-
colName: c.name,
|
|
69
|
-
tableHandler: this,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
/** Do not allow updates to file table unless it's to delete fields */
|
|
73
|
-
if (prostgles.opts.fileTable?.tableName === this.name) {
|
|
74
|
-
update = false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const nonOrderableUD_Types: string[] = [..._PG_geometric, "xml"];
|
|
78
|
-
|
|
79
|
-
const result: ValidatedColumnInfo = {
|
|
80
|
-
...omitKeys(c, ["privileges"]),
|
|
81
|
-
label,
|
|
82
|
-
tsDataType: postgresToTsType(c.udt_name),
|
|
83
|
-
insert:
|
|
84
|
-
insert &&
|
|
85
|
-
!!rules.insert?.fields.includes(c.name) &&
|
|
86
|
-
tableRules?.insert?.forcedData?.[c.name] === undefined &&
|
|
87
|
-
c.is_updatable,
|
|
88
|
-
select: select && !!rules.select?.fields.includes(c.name),
|
|
89
|
-
orderBy:
|
|
90
|
-
select &&
|
|
91
|
-
!!rules.select?.orderByFields.includes(c.name) &&
|
|
92
|
-
!nonOrderableUD_Types.includes(c.udt_name),
|
|
93
|
-
filter: !!rules.select?.filterFields.includes(c.name),
|
|
94
|
-
update:
|
|
95
|
-
update &&
|
|
96
|
-
!!rules.update?.fields.includes(c.name) &&
|
|
97
|
-
tableRules?.update?.forcedData?.[c.name] === undefined &&
|
|
98
|
-
c.is_updatable &&
|
|
99
|
-
dynamicUpdateFields.includes(c.name),
|
|
100
|
-
delete: _delete && !!rules.delete?.filterFields.includes(c.name),
|
|
101
|
-
...(prostgles.tableConfigurator?.getColInfo({
|
|
102
|
-
table: this.name,
|
|
103
|
-
col: c.name,
|
|
104
|
-
lang,
|
|
105
|
-
}) || {}),
|
|
106
|
-
...(fileConfig && { file: fileConfig }),
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
return result;
|
|
110
|
-
})
|
|
111
|
-
.filter((c) => c.select || c.update || c.delete || c.insert);
|
|
22
|
+
const rawColumns = await getRawColumns.call(this, lang, params, tableRules, localParams);
|
|
112
23
|
|
|
113
24
|
const modifiedTableSchema = await this.dboBuilder.prostgles.opts.modifyClientSchema?.(
|
|
114
25
|
{
|
|
115
26
|
name: this.name,
|
|
116
|
-
...(
|
|
27
|
+
...getRawInfo.call(this, lang, tableRules, localParams),
|
|
117
28
|
columns: rawColumns,
|
|
118
29
|
},
|
|
119
30
|
this.config,
|
|
@@ -146,6 +57,108 @@ export async function getColumns(
|
|
|
146
57
|
}
|
|
147
58
|
}
|
|
148
59
|
|
|
60
|
+
/** Permission-filtered columns before client schema customisation. */
|
|
61
|
+
export async function getRawColumns(
|
|
62
|
+
this: ViewHandler,
|
|
63
|
+
lang?: string,
|
|
64
|
+
params?: { rule: "update"; filter: AnyObject },
|
|
65
|
+
tableRules?: ParsedTableRule,
|
|
66
|
+
localParams?: LocalParams,
|
|
67
|
+
): Promise<ValidatedColumnInfo[]> {
|
|
68
|
+
const rules = this.getValidatedRules(tableRules, localParams);
|
|
69
|
+
|
|
70
|
+
let dynamicUpdateFields = this.column_names;
|
|
71
|
+
|
|
72
|
+
if (params && tableRules && isTableHandler(this)) {
|
|
73
|
+
if (
|
|
74
|
+
!isObject(params) ||
|
|
75
|
+
!isObject(params.filter) ||
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
77
|
+
params.rule !== "update"
|
|
78
|
+
) {
|
|
79
|
+
throw (
|
|
80
|
+
"params must be { rule: 'update', filter: object } but received: " + JSON.stringify(params)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!tableRules.update) {
|
|
85
|
+
dynamicUpdateFields = [];
|
|
86
|
+
} else {
|
|
87
|
+
const { filter } = params;
|
|
88
|
+
const updateRules = await this.parseUpdateRules(filter, undefined, tableRules, localParams);
|
|
89
|
+
dynamicUpdateFields = updateRules.fields;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const rawColumns: ValidatedColumnInfo[] = this.columns
|
|
94
|
+
.filter((c) => {
|
|
95
|
+
const { insert, select, update } = rules;
|
|
96
|
+
|
|
97
|
+
return [insert, select, update]
|
|
98
|
+
.filter(isDefined)
|
|
99
|
+
.flatMap((rule) => rule.fields)
|
|
100
|
+
.includes(c.name);
|
|
101
|
+
})
|
|
102
|
+
.map((_c) => {
|
|
103
|
+
const c = { ..._c };
|
|
104
|
+
|
|
105
|
+
const label = capitalizeFirstLetter(c.name, " ");
|
|
106
|
+
|
|
107
|
+
const select = !!c.privileges.SELECT;
|
|
108
|
+
const insert = !!c.privileges.INSERT;
|
|
109
|
+
const _delete = !!this.tableOrViewInfo.privileges.delete;
|
|
110
|
+
let update = !!c.privileges.UPDATE;
|
|
111
|
+
|
|
112
|
+
const prostgles = this.dboBuilder.prostgles;
|
|
113
|
+
const fileConfig = getFileColumnInfo({
|
|
114
|
+
colName: c.name,
|
|
115
|
+
tableHandler: this,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/** Do not allow updates to file table unless it's to delete fields */
|
|
119
|
+
if (prostgles.opts.fileTable?.tableName === this.name) {
|
|
120
|
+
update = false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const nonOrderableUD_Types: string[] = [..._PG_geometric, "xml"];
|
|
124
|
+
|
|
125
|
+
const result: ValidatedColumnInfo = {
|
|
126
|
+
...omitKeys(c, ["privileges"]),
|
|
127
|
+
label,
|
|
128
|
+
tsDataType: postgresToTsType(c.udt_name),
|
|
129
|
+
insert:
|
|
130
|
+
insert &&
|
|
131
|
+
!!rules.insert?.fields.includes(c.name) &&
|
|
132
|
+
tableRules?.insert?.forcedData?.[c.name] === undefined &&
|
|
133
|
+
c.is_updatable,
|
|
134
|
+
select: select && !!rules.select?.fields.includes(c.name),
|
|
135
|
+
orderBy:
|
|
136
|
+
select &&
|
|
137
|
+
!!rules.select?.orderByFields.includes(c.name) &&
|
|
138
|
+
!nonOrderableUD_Types.includes(c.udt_name),
|
|
139
|
+
filter: !!rules.select?.filterFields.includes(c.name),
|
|
140
|
+
update:
|
|
141
|
+
update &&
|
|
142
|
+
!!rules.update?.fields.includes(c.name) &&
|
|
143
|
+
tableRules?.update?.forcedData?.[c.name] === undefined &&
|
|
144
|
+
c.is_updatable &&
|
|
145
|
+
dynamicUpdateFields.includes(c.name),
|
|
146
|
+
delete: _delete && !!rules.delete?.filterFields.includes(c.name),
|
|
147
|
+
...(prostgles.tableConfigurator?.getColInfo({
|
|
148
|
+
table: this.name,
|
|
149
|
+
col: c.name,
|
|
150
|
+
lang,
|
|
151
|
+
}) || {}),
|
|
152
|
+
...(fileConfig && { file: fileConfig }),
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return result;
|
|
156
|
+
})
|
|
157
|
+
.filter((c) => c.select || c.update || c.delete || c.insert);
|
|
158
|
+
|
|
159
|
+
return rawColumns;
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
const capitalizeFirstLetter = (string: string, nonAlphaNumericReplacement = " ") => {
|
|
150
163
|
const str = string.replace(/[\W_]+/g, nonAlphaNumericReplacement);
|
|
151
164
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
@@ -107,6 +107,7 @@ export class QueryStreamer {
|
|
|
107
107
|
let streamState: "started" | "ended" | "errored" | undefined;
|
|
108
108
|
|
|
109
109
|
const startStream = async (client: pg.Client | undefined, query: ClientStreamedRequest) => {
|
|
110
|
+
await this.dboBuilder.prostgles.schemaReady;
|
|
110
111
|
await this.dboBuilder.cacheDBTypes();
|
|
111
112
|
const socketQuery = this.socketQueries.get(socketId)?.get(id);
|
|
112
113
|
if (!socketQuery) {
|
|
@@ -25,7 +25,7 @@ export const getSchemaFilter = (schema: ProstglesInitOptions["schemaFilter"] = {
|
|
|
25
25
|
// TODO: Add a onSocketConnect timeout for this query.
|
|
26
26
|
// Reason: this query gets blocked by prostgles.app_triggers from PubSubManager.addTrigger in some cases (pg_dump locks that table)
|
|
27
27
|
export async function getTablesForSchemaPostgresSQL(
|
|
28
|
-
{ db
|
|
28
|
+
{ db }: Pick<DboBuilder, "db">,
|
|
29
29
|
{
|
|
30
30
|
schemaFilter,
|
|
31
31
|
ddlWithRollback,
|
|
@@ -288,7 +288,7 @@ export async function getTablesForSchemaPostgresSQL(
|
|
|
288
288
|
});
|
|
289
289
|
|
|
290
290
|
/** Get view reference cols (based on parent table) */
|
|
291
|
-
const viewReferenceColumns = await getViewReferenceColumns(table, tableSchemaList,
|
|
291
|
+
const viewReferenceColumns = await getViewReferenceColumns(table, tableSchemaList, db);
|
|
292
292
|
|
|
293
293
|
table.columns = table.columns.map((col) => {
|
|
294
294
|
if (col.has_default) {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { isDefined
|
|
2
|
-
import type {
|
|
1
|
+
import { isDefined } from "prostgles-types";
|
|
2
|
+
import type { DB } from "../../Prostgles";
|
|
3
|
+
import { getDbTypes, getDetailedFieldInfo } from "../runSql/runSqlUtils";
|
|
3
4
|
import type { TableSchema, TableSchemaColumn } from "../DboBuilderTypes";
|
|
4
5
|
|
|
5
6
|
export const getViewReferenceColumns = async (
|
|
6
7
|
table: TableSchema,
|
|
7
8
|
tableSchemaList: TableSchema[],
|
|
8
|
-
|
|
9
|
+
db: DB
|
|
9
10
|
) => {
|
|
10
11
|
const viewReferenceColumns: Pick<TableSchemaColumn, "name" | "references">[] = [];
|
|
11
12
|
if (!table.is_view || !table.view_definition) {
|
|
@@ -16,12 +17,10 @@ export const getViewReferenceColumns = async (
|
|
|
16
17
|
table.view_definition.endsWith(";") ?
|
|
17
18
|
table.view_definition.slice(0, -1)
|
|
18
19
|
: table.view_definition;
|
|
19
|
-
const { fields
|
|
20
|
+
const { fields } = await db.result(
|
|
20
21
|
`SELECT * FROM \n ( ${view_definition} \n) t LIMIT 0`,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
undefined
|
|
24
|
-
)) as SQLResult<undefined>;
|
|
22
|
+
);
|
|
23
|
+
const viewFieldsWithInfo = getDetailedFieldInfo(await getDbTypes(db), fields);
|
|
25
24
|
const viewTables = tableSchemaList.filter((r) =>
|
|
26
25
|
viewFieldsWithInfo.some((f) => f.tableID === r.oid)
|
|
27
26
|
);
|
package/lib/Prostgles.ts
CHANGED
|
@@ -63,6 +63,9 @@ import type { getAdminClient } from "./DboBuilder/runSql/getAdminClient";
|
|
|
63
63
|
import type { TableHandler } from "./DboBuilder/TableHandler/TableHandler";
|
|
64
64
|
import { getFileTableConfig } from "./StorageClient/getFileTableConfig";
|
|
65
65
|
import { dirname } from "path";
|
|
66
|
+
import { getAuditTableConfig, type ParsedAuditConfig } from "./Audit/getAuditTableConfig";
|
|
67
|
+
import { syncTableTriggers } from "./TableConfig/syncTableTriggers";
|
|
68
|
+
import { isManagedTriggerName } from "./TableConfig/managedTriggerNames";
|
|
66
69
|
|
|
67
70
|
export class Prostgles {
|
|
68
71
|
/**
|
|
@@ -106,6 +109,16 @@ export class Prostgles {
|
|
|
106
109
|
|
|
107
110
|
keywords = DEFAULT_KEYWORDS;
|
|
108
111
|
loaded = false;
|
|
112
|
+
/** Only schema setup uses this original connection. Application handlers use db. */
|
|
113
|
+
dbForSchema?: DB;
|
|
114
|
+
schemaReady: Promise<void> = Promise.resolve();
|
|
115
|
+
|
|
116
|
+
runSchemaQueries = (queries: () => Promise<void>) => {
|
|
117
|
+
this.schemaReady = this.schemaReady.catch(() => {}).then(queries);
|
|
118
|
+
void this.schemaReady.catch(() => {});
|
|
119
|
+
return this.schemaReady;
|
|
120
|
+
};
|
|
121
|
+
parsedAuditConfig?: ParsedAuditConfig;
|
|
109
122
|
preparingTableConfig = false;
|
|
110
123
|
|
|
111
124
|
dbEventsManager?: DBEventsManager;
|
|
@@ -116,7 +129,15 @@ export class Prostgles {
|
|
|
116
129
|
tableConfigurator?: TableConfigurator;
|
|
117
130
|
|
|
118
131
|
get mergedTableConfig() {
|
|
119
|
-
|
|
132
|
+
for (const [tableName, table] of Object.entries(this.opts.tableConfig ?? {})) {
|
|
133
|
+
for (const name of Object.keys(table.triggers ?? {})) {
|
|
134
|
+
if (isManagedTriggerName(name)) {
|
|
135
|
+
throw new Error(`Trigger ${tableName}.${name} uses a prefix reserved for prostgles`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const config = getFileTableConfig(this);
|
|
140
|
+
return { ...config, tableConfig: getAuditTableConfig(this, config.tableConfig) };
|
|
120
141
|
}
|
|
121
142
|
|
|
122
143
|
isMedia(tableName: string) {
|
|
@@ -148,6 +169,7 @@ export class Prostgles {
|
|
|
148
169
|
onQuery: 1,
|
|
149
170
|
onConnectionError: 1,
|
|
150
171
|
tableConfig: 1,
|
|
172
|
+
audit: 1,
|
|
151
173
|
tableHooks: 1,
|
|
152
174
|
tableConfigMigrations: 1,
|
|
153
175
|
onNotice: 1,
|
|
@@ -286,10 +308,18 @@ export class Prostgles {
|
|
|
286
308
|
|
|
287
309
|
/** Rebuilds the DBO and replaces the application context. */
|
|
288
310
|
refreshDBO = async () => {
|
|
311
|
+
this.loaded = false;
|
|
289
312
|
await this.cleanupContext();
|
|
290
|
-
|
|
313
|
+
await this.runSchemaQueries(async () => {
|
|
314
|
+
await this.rebuildDBO();
|
|
315
|
+
if (this.opts.audit || this.parsedAuditConfig) {
|
|
316
|
+
await syncTableTriggers(this);
|
|
317
|
+
await this.rebuildDBO();
|
|
318
|
+
}
|
|
319
|
+
});
|
|
291
320
|
await this.createContext({ type: "dbo.refresh" });
|
|
292
|
-
|
|
321
|
+
this.loaded = true;
|
|
322
|
+
return this.dbo!;
|
|
293
323
|
};
|
|
294
324
|
|
|
295
325
|
initRestApi = () => {
|
|
@@ -307,7 +337,6 @@ export class Prostgles {
|
|
|
307
337
|
if (this.tableConfigurator?.initialising) {
|
|
308
338
|
console.error("TableConfigurator WILL deadlock", { reason });
|
|
309
339
|
}
|
|
310
|
-
await this.tableConfigurator?.destroy();
|
|
311
340
|
this.tableConfigurator = new TableConfigurator(this);
|
|
312
341
|
try {
|
|
313
342
|
const now = Date.now();
|
|
@@ -323,7 +352,7 @@ export class Prostgles {
|
|
|
323
352
|
duration: Date.now() - now,
|
|
324
353
|
});
|
|
325
354
|
} catch (e) {
|
|
326
|
-
if (this.opts.tableConfigMigrations?.silentFail === false) {
|
|
355
|
+
if (!this.opts.audit && this.opts.tableConfigMigrations?.silentFail === false) {
|
|
327
356
|
console.error("TableConfigurator silentFail: ", e);
|
|
328
357
|
} else {
|
|
329
358
|
throw e;
|
package/lib/ProstglesTypes.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { StorageClient } from "./StorageClient/StorageClientTypes";
|
|
|
14
14
|
import type { PGConstraint } from "./TableConfig/fetchTableConstraints";
|
|
15
15
|
import type { TableConfig } from "./TableConfig/TableConfigTypes";
|
|
16
16
|
import type { TableHooks } from "./TableHooks/TableHooks";
|
|
17
|
+
import type { SchemaConfigAudit } from "./Audit/AuditTypes";
|
|
17
18
|
|
|
18
19
|
import type { PRGLIOSocket } from "./DboBuilder/DboBuilder";
|
|
19
20
|
|
|
@@ -312,6 +313,8 @@ export type ProstglesInitOptions<
|
|
|
312
313
|
* made to the database schema through SQL queries
|
|
313
314
|
*/
|
|
314
315
|
tableConfig?: TableConfig;
|
|
316
|
+
/** Audit committed row changes after bootstrap, before application callbacks run. */
|
|
317
|
+
audit?: SchemaConfigAudit<S>;
|
|
315
318
|
|
|
316
319
|
/**
|
|
317
320
|
* Migration logic used when the new tableConfig version is higher than the one in the database.
|
|
@@ -6,7 +6,7 @@ import type { DboBuilder } from "../DboBuilder/DboBuilder";
|
|
|
6
6
|
export const getCreatePubSubManagerError = async (
|
|
7
7
|
dboBuilder: DboBuilder
|
|
8
8
|
): Promise<string | undefined> => {
|
|
9
|
-
const db = dboBuilder.
|
|
9
|
+
const db = dboBuilder.prostgles.dbForSchema!;
|
|
10
10
|
|
|
11
11
|
const canExecute = await getCanExecute(db);
|
|
12
12
|
if (!canExecute) return "Cannot run EXECUTE statements on this connection";
|
|
@@ -500,19 +500,19 @@ COMMIT;
|
|
|
500
500
|
export const getPubSubManagerInitQuery = async function (
|
|
501
501
|
this: DboBuilder,
|
|
502
502
|
): Promise<string | undefined> {
|
|
503
|
-
const versionNum = await this.
|
|
503
|
+
const versionNum = await this.prostgles.dbForSchema!.one("SELECT current_setting('server_version_num')::int as val");
|
|
504
504
|
const initQuery = getInitQuery(this.prostgles.opts.DEBUG_MODE, versionNum.val);
|
|
505
|
-
const { schema_md5 = "none" } = await this.
|
|
505
|
+
const { schema_md5 = "none" } = await this.prostgles.dbForSchema!.oneOrNone("SELECT md5($1) as schema_md5", [
|
|
506
506
|
initQuery.trim(),
|
|
507
507
|
]);
|
|
508
508
|
const query = pgp.as.format(initQuery, { schema_md5, version });
|
|
509
|
-
const existingSchema = await this.
|
|
509
|
+
const existingSchema = await this.prostgles.dbForSchema!.any(PROSTGLES_SCHEMA_EXISTS_QUERY);
|
|
510
510
|
if (!existingSchema.length) {
|
|
511
511
|
console.log("getPubSubManagerInitQuery: No prostgles.versions table found. Creating...");
|
|
512
512
|
return query;
|
|
513
513
|
}
|
|
514
514
|
const { data: existingSchemaVersions } = await tryCatchV2(async () => {
|
|
515
|
-
const existingSchemaVersions = await this.
|
|
515
|
+
const existingSchemaVersions = await this.prostgles.dbForSchema!.any(PROSTGLES_SCHEMA_VERSION_OK_QUERY, {
|
|
516
516
|
schema_md5,
|
|
517
517
|
version,
|
|
518
518
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isAuditTable } from "../Audit/getAuditTableConfig";
|
|
1
2
|
import { getObjectEntries, isObject } from "prostgles-types";
|
|
2
3
|
import type { AuthResultWithSID } from "../Auth/AuthTypes";
|
|
3
4
|
import type { TableHandler } from "../DboBuilder/TableHandler/TableHandler";
|
|
@@ -42,7 +43,7 @@ export async function getTableRulesWithoutFileTable(
|
|
|
42
43
|
|
|
43
44
|
const isStarOrTrue = (value: any): value is "*" | true => value === "*" || value === true;
|
|
44
45
|
const { privileges } = tableHandler.tableOrViewInfo;
|
|
45
|
-
const
|
|
46
|
+
const rawTableRulesObject =
|
|
46
47
|
isStarOrTrue(rawTableRule) ?
|
|
47
48
|
{
|
|
48
49
|
select: privileges.select ? TABLE_RULE_NO_LIMITS.select : undefined,
|
|
@@ -52,6 +53,10 @@ export async function getTableRulesWithoutFileTable(
|
|
|
52
53
|
}
|
|
53
54
|
: rawTableRule;
|
|
54
55
|
|
|
56
|
+
const tableRulesObject = isAuditTable(this.prostgles, tableName)
|
|
57
|
+
? { select: rawTableRulesObject.select, insert: undefined, update: undefined, delete: undefined }
|
|
58
|
+
: rawTableRulesObject;
|
|
59
|
+
|
|
55
60
|
const selectRule =
|
|
56
61
|
!tableRulesObject.select ? undefined
|
|
57
62
|
: isStarOrTrue(tableRulesObject.select) ? TABLE_RULE_NO_LIMITS.select
|
|
@@ -31,7 +31,7 @@ type BaseTableDefinition = {
|
|
|
31
31
|
* Use "before" when you need to change the data before the action
|
|
32
32
|
*/
|
|
33
33
|
type: "before" | "after" | "instead of";
|
|
34
|
-
actions: ("insert" | "update" | "delete")[];
|
|
34
|
+
actions: ("insert" | "update" | "delete" | "truncate")[];
|
|
35
35
|
forEach: "statement" | "row";
|
|
36
36
|
/**
|
|
37
37
|
* @example
|
|
@@ -23,8 +23,8 @@ export class TableConfigurator {
|
|
|
23
23
|
return this.prostgles.dbo;
|
|
24
24
|
}
|
|
25
25
|
get db(): DB {
|
|
26
|
-
if (!this.prostgles.
|
|
27
|
-
return this.prostgles.
|
|
26
|
+
if (!this.prostgles.dbForSchema) throw "Schema database connection missing";
|
|
27
|
+
return this.prostgles.dbForSchema;
|
|
28
28
|
}
|
|
29
29
|
prostgles: Prostgles;
|
|
30
30
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getManagedTriggerName } from "./managedTriggerNames";
|
|
1
2
|
import { as } from "pg-promise";
|
|
2
3
|
import { isDefined } from "prostgles-types";
|
|
3
4
|
import type { DB } from "../initProstgles";
|
|
@@ -226,14 +227,14 @@ const getTriggerQueries = (
|
|
|
226
227
|
];
|
|
227
228
|
|
|
228
229
|
trigger.actions.forEach((action) => {
|
|
229
|
-
const triggerActionName = triggerFuncName
|
|
230
|
+
const triggerActionName = getManagedTriggerName(triggerFuncName, action);
|
|
230
231
|
|
|
231
232
|
const triggerActionNameParsed = asName(triggerActionName);
|
|
232
233
|
|
|
233
234
|
const newTableName = action !== "delete" ? "NEW TABLE AS new_table" : "";
|
|
234
235
|
const oldTableName = action !== "insert" ? "OLD TABLE AS old_table" : "";
|
|
235
236
|
const transitionTables =
|
|
236
|
-
trigger.forEach === "row" ? "" : `REFERENCING ${newTableName} ${oldTableName}`;
|
|
237
|
+
trigger.forEach === "row" || trigger.type !== "after" || action === "truncate" ? "" : `REFERENCING ${newTableName} ${oldTableName}`;
|
|
237
238
|
queries.push(`
|
|
238
239
|
CREATE TRIGGER ${triggerActionNameParsed}
|
|
239
240
|
${trigger.type} ${action} ON ${tableName}
|