prostgles-server 4.2.619 → 4.2.621
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/debug/access-profile-source.patch +14 -0
- package/debug/client-profile-perf.cjs +17 -0
- package/debug/client-publish-types-test.log +16 -0
- package/debug/client-schema-test.log +10 -0
- package/debug/client-schema-types/DBGeneratedSchema.ts +59 -0
- package/debug/client-typecheck.ts +11 -0
- package/debug/profile-perf.cjs +26 -0
- package/debug/prostgles-types-4.0.282.tgz +0 -0
- package/debug/publish-schema-test.log +16 -0
- package/debug/run-client-schema.cjs +3 -0
- package/debug/run-publish-schema.cjs +3 -0
- package/debug/server-lib-tests.log +28 -0
- package/debug/types-pack.log +162 -0
- package/dist/DBSchemaBuilder/DBSchemaBuilder.d.ts +6 -0
- package/dist/DBSchemaBuilder/DBSchemaBuilder.d.ts.map +1 -1
- package/dist/DBSchemaBuilder/constants.d.ts +2 -0
- package/dist/DBSchemaBuilder/constants.d.ts.map +1 -0
- package/dist/DBSchemaBuilder/constants.js +5 -0
- package/dist/DBSchemaBuilder/constants.js.map +1 -0
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.d.ts +9 -0
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.d.ts.map +1 -0
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js +97 -0
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js.map +1 -0
- package/dist/DBSchemaBuilder/getColumnTypescriptDefinition.js +2 -2
- package/dist/DBSchemaBuilder/getDBGeneratedSchema.d.ts +3 -1
- package/dist/DBSchemaBuilder/getDBGeneratedSchema.d.ts.map +1 -1
- package/dist/DBSchemaBuilder/getDBGeneratedSchema.js +7 -5
- package/dist/DBSchemaBuilder/getDBGeneratedSchema.js.map +1 -1
- package/dist/DBSchemaBuilder/getPublishSchemas.d.ts +4 -0
- package/dist/DBSchemaBuilder/getPublishSchemas.d.ts.map +1 -0
- package/dist/DBSchemaBuilder/getPublishSchemas.js +34 -0
- package/dist/DBSchemaBuilder/getPublishSchemas.js.map +1 -0
- package/dist/DboBuilder/DboBuilder.d.ts +5 -8
- package/dist/DboBuilder/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder/DboBuilder.js +11 -14
- package/dist/DboBuilder/DboBuilder.js.map +1 -1
- package/dist/DboBuilder/TableHandler/TableHandler.d.ts +1 -1
- package/dist/Prostgles.d.ts +3 -2
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +9 -3
- package/dist/Prostgles.js.map +1 -1
- package/dist/PublishParser/PublishParser.d.ts +3 -2
- package/dist/PublishParser/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser/PublishParser.js +16 -5
- package/dist/PublishParser/PublishParser.js.map +1 -1
- package/dist/PublishParser/defineServerFunction.d.ts +5 -3
- package/dist/PublishParser/defineServerFunction.d.ts.map +1 -1
- package/dist/PublishParser/defineServerFunction.js.map +1 -1
- package/dist/PublishParser/getFileTableRules.d.ts +2 -2
- package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
- package/dist/PublishParser/getFileTableRules.js +2 -2
- package/dist/PublishParser/getFileTableRules.js.map +1 -1
- package/dist/PublishParser/getPublishedTableNames.d.ts +4 -0
- package/dist/PublishParser/getPublishedTableNames.d.ts.map +1 -0
- package/dist/PublishParser/getPublishedTableNames.js +23 -0
- package/dist/PublishParser/getPublishedTableNames.js.map +1 -0
- package/dist/PublishParser/getSchemaFromPublish.d.ts.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.js +2 -13
- package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.d.ts +13 -6
- package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
- package/dist/PublishParser/validatePublishProfiles.d.ts +7 -0
- package/dist/PublishParser/validatePublishProfiles.d.ts.map +1 -0
- package/dist/PublishParser/validatePublishProfiles.js +27 -0
- package/dist/PublishParser/validatePublishProfiles.js.map +1 -0
- package/dist/SchemaWatch/SchemaWatch.js +1 -1
- package/dist/SchemaWatch/SchemaWatch.js.map +1 -1
- package/dist/TableHooks/TableHooks.d.ts +7 -5
- package/dist/TableHooks/TableHooks.d.ts.map +1 -1
- package/dist/WebsocketAPI/getClientHandlers.d.ts +3 -3
- package/dist/WebsocketAPI/getClientHandlers.d.ts.map +1 -1
- package/dist/WebsocketAPI/getClientHandlers.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/initProstgles.d.ts +2 -2
- package/dist/initProstgles.d.ts.map +1 -1
- package/dist/initProstgles.js +2 -4
- package/dist/initProstgles.js.map +1 -1
- package/dist/updateConfiguration.d.ts.map +1 -1
- package/dist/updateConfiguration.js +6 -2
- package/dist/updateConfiguration.js.map +1 -1
- package/eslint.config.mjs +1 -1
- package/lib/DBSchemaBuilder/DBSchemaBuilder.ts +10 -0
- package/lib/DBSchemaBuilder/constants.ts +1 -0
- package/lib/DBSchemaBuilder/getClientDBGeneratedSchemas.ts +116 -0
- package/lib/DBSchemaBuilder/getColumnTypescriptDefinition.ts +2 -2
- package/lib/DBSchemaBuilder/getDBGeneratedSchema.ts +11 -4
- package/lib/DBSchemaBuilder/getPublishSchemas.ts +41 -0
- package/lib/DboBuilder/DboBuilder.ts +15 -22
- package/lib/Prostgles.ts +10 -4
- package/lib/PublishParser/PublishParser.ts +25 -5
- package/lib/PublishParser/defineServerFunction.ts +5 -3
- package/lib/PublishParser/getFileTableRules.ts +3 -2
- package/lib/PublishParser/getPublishedTableNames.ts +29 -0
- package/lib/PublishParser/getSchemaFromPublish.ts +2 -17
- package/lib/PublishParser/publishTypesAndUtils.ts +13 -5
- package/lib/PublishParser/validatePublishProfiles.ts +22 -0
- package/lib/SchemaWatch/SchemaWatch.ts +1 -1
- package/lib/TableHooks/TableHooks.ts +14 -7
- package/lib/WebsocketAPI/getClientHandlers.ts +4 -4
- package/lib/index.ts +2 -2
- package/lib/initProstgles.ts +7 -19
- package/lib/updateConfiguration.ts +5 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateConfiguration.js","sourceRoot":"","sources":["../lib/updateConfiguration.ts"],"names":[],"mappings":";;;AAAA,qDAAiF;AAI1E,MAAM,mBAAmB,GAAG,KAAK,EACtC,IAAe,EACf,OAA6B,EAC7B,OAAyC,EACzC,KAAY,EACZ,EAAE;IACF,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACzB,MAAM,kBAAkB,GAAG,IAAA,yBAAO,EAAC,OAAO,CAAC;SACxC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,6DAA6D;QAC7D,IAAI,KAAK,IAAI,CAAC,IAAA,yBAAO,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAChD,YAAY;YACZ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,OAAO;IACT,CAAC,CAAC;SACD,MAAM,CAAC,2BAAS,CAAC,CAAC;IACrB,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC;QAC/B,MAAM,IAAI,CAAC,WAAW,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IAED,IAAI,IAAA,0BAAQ,EAAC,kBAAkB,EAAE,SAAS,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;IACD,IAAI,IAAA,0BAAQ,EAAC,kBAAkB,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;IAC1B,CAAC;IACD,IAAI,IAAA,0BAAQ,EAAC,kBAAkB,EAAE,MAAM,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,IAAA,0BAAQ,EAAC,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACvC,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IACE,IAAA,0BAAQ,EAAC,kBAAkB,EAAE,qBAAqB,CAAC;QACnD,IAAA,0BAAQ,EAAC,kBAAkB,EAAE,+BAA+B,CAAC,EAC7D,CAAC;QACD,IAAI,CAAC,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"updateConfiguration.js","sourceRoot":"","sources":["../lib/updateConfiguration.ts"],"names":[],"mappings":"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"}
|
package/eslint.config.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import tseslint from "typescript-eslint";
|
|
|
3
3
|
|
|
4
4
|
export default tseslint.config(
|
|
5
5
|
{
|
|
6
|
-
ignores: ["node_modules", "dist", "examples", "**/*.d.ts", "tests", "docs"],
|
|
6
|
+
ignores: ["node_modules", "dist", "debug", "examples", "**/*.d.ts", "tests", "docs"],
|
|
7
7
|
},
|
|
8
8
|
eslint.configs.recommended,
|
|
9
9
|
tseslint.configs.recommendedTypeChecked,
|
|
@@ -27,6 +27,16 @@ export type DBOFullyTyped<
|
|
|
27
27
|
> = DBTableHandlersFromSchema<Schema> &
|
|
28
28
|
DBHandlerServerWithTx<DBTableHandlersFromSchema<Schema>, WithTransactions>;
|
|
29
29
|
|
|
30
|
+
/** Publish-aware server wrappers for client requests; transactions and isView are unavailable. */
|
|
31
|
+
export type DBOFullyTypedClient<Schema = void> =
|
|
32
|
+
Schema extends DBSchema ?
|
|
33
|
+
{
|
|
34
|
+
[TName in keyof Schema]:
|
|
35
|
+
| TableHandler<Schema[TName]["columns"], Schema, TName>
|
|
36
|
+
| (Schema[TName] extends { optional: true } ? undefined : never);
|
|
37
|
+
}
|
|
38
|
+
: Record<string, Partial<TableHandler>>;
|
|
39
|
+
|
|
30
40
|
export type PublishFullyTyped<Schema = void> =
|
|
31
41
|
Schema extends DBSchema ?
|
|
32
42
|
{
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DB_GENERATED_SCHEMA_NAME = "DBGeneratedSchema";
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { DB_GENERATED_SCHEMA_NAME } from "./constants";
|
|
2
|
+
import type { DBSchemaTable, TableSchema } from "prostgles-types";
|
|
3
|
+
import type { TableConfig } from "../TableConfig/TableConfigTypes";
|
|
4
|
+
|
|
5
|
+
/** Permissions compiled from publish profiles at startup. */
|
|
6
|
+
export type ClientSchemaProfiles = Record<string, { tableSchema: DBSchemaTable[] }>;
|
|
7
|
+
|
|
8
|
+
export const getClientDBGeneratedSchemas = (
|
|
9
|
+
profiles: ClientSchemaProfiles,
|
|
10
|
+
tables: TableSchema[],
|
|
11
|
+
config: TableConfig | undefined,
|
|
12
|
+
): string => {
|
|
13
|
+
const entries = Object.entries(profiles).sort(([a], [b]) => a.localeCompare(b));
|
|
14
|
+
if (!entries.length) return "";
|
|
15
|
+
for (const [name, schema] of entries) {
|
|
16
|
+
validateClientSchemaName(name);
|
|
17
|
+
for (const table of schema.tableSchema) {
|
|
18
|
+
const base = tables.find((t) => t.name === table.name);
|
|
19
|
+
if (!base || table.columns.some((c) => !base.columns.some((b) => b.name === c.name))) {
|
|
20
|
+
throw new Error(`Cannot generate ${name}: unknown table or column in ${table.name}.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const generate = (name: string, schemas: ClientSchemaProfiles[string][]) => {
|
|
26
|
+
const definitions = tables
|
|
27
|
+
.slice()
|
|
28
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
29
|
+
.flatMap((table) => {
|
|
30
|
+
const published = schemas.map((s) => s.tableSchema.find((t) => t.name === table.name));
|
|
31
|
+
if (!published.some(Boolean)) return [];
|
|
32
|
+
const inserting = published.filter((t) => t?.publishInfo.insert);
|
|
33
|
+
const tableType = `${DB_GENERATED_SCHEMA_NAME}[${JSON.stringify(table.name)}]`;
|
|
34
|
+
const required: string[] = [];
|
|
35
|
+
const optional: string[] = [];
|
|
36
|
+
const excluded: string[] = [];
|
|
37
|
+
for (const column of table.columns.slice().sort((a, b) => a.name.localeCompare(b.name))) {
|
|
38
|
+
const writable = inserting.map(
|
|
39
|
+
(t) => !!t?.columns.find((c) => c.name === column.name)?.insert,
|
|
40
|
+
);
|
|
41
|
+
if (!writable.some(Boolean)) {
|
|
42
|
+
excluded.push(`${JSON.stringify(column.name)}?: never`);
|
|
43
|
+
} else if (
|
|
44
|
+
!writable.every(Boolean) ||
|
|
45
|
+
config?.[table.name]?.syncConfig?.synced_field === column.name
|
|
46
|
+
) {
|
|
47
|
+
optional.push(column.name);
|
|
48
|
+
} else {
|
|
49
|
+
required.push(column.name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const input =
|
|
53
|
+
!inserting.length ? "never" : (
|
|
54
|
+
[
|
|
55
|
+
required.length ? `Pick<${tableType}["columns"], ${keys(required)}>` : "",
|
|
56
|
+
optional.length ? `Partial<Pick<${tableType}["columns"], ${keys(optional)}>>` : "",
|
|
57
|
+
excluded.length ? `{ ${excluded.join("; ")} }` : "",
|
|
58
|
+
]
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.join(" & ") || "Record<string, never>"
|
|
61
|
+
);
|
|
62
|
+
const updating = published.filter((t) => t?.publishInfo.update);
|
|
63
|
+
const updateAllowed = table.columns
|
|
64
|
+
.filter((column) =>
|
|
65
|
+
updating.some((t) => t?.columns.some((c) => c.name === column.name && c.update)),
|
|
66
|
+
)
|
|
67
|
+
.map((column) => column.name)
|
|
68
|
+
.sort();
|
|
69
|
+
const updateExcluded = table.columns
|
|
70
|
+
.filter((column) => !updateAllowed.includes(column.name))
|
|
71
|
+
.map((column) => `${JSON.stringify(column.name)}?: never`)
|
|
72
|
+
.sort();
|
|
73
|
+
const updateInput =
|
|
74
|
+
!updating.length ? "never" : (
|
|
75
|
+
[
|
|
76
|
+
updateAllowed.length ?
|
|
77
|
+
`Partial<import("prostgles-types").UpsertDataToPGCast<Pick<${tableType}["columns"], ${keys(updateAllowed)}>>>`
|
|
78
|
+
: "",
|
|
79
|
+
updateExcluded.length ? `{ ${updateExcluded.join("; ")} }` : "",
|
|
80
|
+
]
|
|
81
|
+
.filter(Boolean)
|
|
82
|
+
.join(" & ") || "Record<string, never>"
|
|
83
|
+
);
|
|
84
|
+
const optionalTable = published.every(Boolean) ? "" : " optional: true;";
|
|
85
|
+
return [
|
|
86
|
+
` ${JSON.stringify(table.name)}: ${tableType} & { insertColumns: ${input}; updateColumns: ${updateInput};${optionalTable} };`,
|
|
87
|
+
];
|
|
88
|
+
});
|
|
89
|
+
return `export type ${name} = {\n${definitions.join("\n")}\n};`;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
return [
|
|
93
|
+
"/** Publish access profiles. Row types retain the database schema; runtime permissions still apply. */",
|
|
94
|
+
...entries.map(([name, schema]) => generate(name, [schema])),
|
|
95
|
+
"/** Permissive write inputs across all supplied profiles; tables missing from a profile are optional. */",
|
|
96
|
+
generate(
|
|
97
|
+
"ClientDBSchema",
|
|
98
|
+
entries.map(([, schema]) => schema),
|
|
99
|
+
),
|
|
100
|
+
].join("\n\n");
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const keys = (names: string[]) => names.map((name) => JSON.stringify(name)).join(" | ");
|
|
104
|
+
const reservedNames = new Set([
|
|
105
|
+
DB_GENERATED_SCHEMA_NAME,
|
|
106
|
+
"DBSchema",
|
|
107
|
+
"DBSchemaForInsert",
|
|
108
|
+
"ClientDBSchema",
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
export const validateClientSchemaName = (name: string) => {
|
|
112
|
+
// Requiring a Schema suffix also avoids TypeScript keywords and primitive type names.
|
|
113
|
+
if (!/^[A-Za-z_$][\w$]*Schema$/.test(name) || reservedNames.has(name)) {
|
|
114
|
+
throw new Error(`Invalid client schema name: ${name}. Use a unique name ending in Schema.`);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
@@ -25,8 +25,8 @@ export const getColumnTypescriptDefinition = ({
|
|
|
25
25
|
column: TableSchema["columns"][number];
|
|
26
26
|
}) => {
|
|
27
27
|
/**
|
|
28
|
-
* Columns that are nullable or have default values can be
|
|
29
|
-
* Non nullable columns with default values cannot
|
|
28
|
+
* Columns that are nullable or have default values can be omitted from an insert
|
|
29
|
+
* Non nullable columns with default values cannot contain null values in an insert so they must contain a valid value or be omitted
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
const dataType = getDataType({
|
|
@@ -1,15 +1,22 @@
|
|
|
1
|
+
import { DB_GENERATED_SCHEMA_NAME } from "./constants";
|
|
1
2
|
import { isDefined, isEmpty, type TableSchema } from "prostgles-types";
|
|
2
3
|
import type { TableConfig } from "../TableConfig/TableConfigTypes";
|
|
3
4
|
import { escapeTSNames } from "../utils/utils";
|
|
4
5
|
import { getColumnTypescriptDefinition } from "./getColumnTypescriptDefinition";
|
|
5
6
|
import { fromEntries } from "../PublishParser/applyScopeToTableRules";
|
|
7
|
+
import {
|
|
8
|
+
getClientDBGeneratedSchemas,
|
|
9
|
+
type ClientSchemaProfiles,
|
|
10
|
+
} from "./getClientDBGeneratedSchemas";
|
|
6
11
|
|
|
7
12
|
export const getDBGeneratedSchema = ({
|
|
8
13
|
config,
|
|
9
14
|
tablesOrViews,
|
|
15
|
+
clientSchemas,
|
|
10
16
|
}: {
|
|
11
17
|
config: TableConfig | undefined;
|
|
12
18
|
tablesOrViews: TableSchema[];
|
|
19
|
+
clientSchemas?: ClientSchemaProfiles;
|
|
13
20
|
}): string => {
|
|
14
21
|
const tables: string[] = [];
|
|
15
22
|
|
|
@@ -61,7 +68,7 @@ export const getDBGeneratedSchema = ({
|
|
|
61
68
|
};\n `);
|
|
62
69
|
});
|
|
63
70
|
return `
|
|
64
|
-
export type
|
|
71
|
+
export type ${DB_GENERATED_SCHEMA_NAME} = {
|
|
65
72
|
${tables.join("")}
|
|
66
73
|
}
|
|
67
74
|
|
|
@@ -69,14 +76,14 @@ export type DBGeneratedSchema = {
|
|
|
69
76
|
* Data types as expected when selecting from the database
|
|
70
77
|
* */
|
|
71
78
|
export type DBSchema = {
|
|
72
|
-
[K in keyof
|
|
79
|
+
[K in keyof ${DB_GENERATED_SCHEMA_NAME}]: Required<${DB_GENERATED_SCHEMA_NAME}[K]["columns"]>;
|
|
73
80
|
};
|
|
74
81
|
|
|
75
82
|
/**
|
|
76
83
|
* Data types as expected when inserting into the database (optional fields might be nullable/with defaults)
|
|
77
84
|
* */
|
|
78
85
|
export type DBSchemaForInsert = {
|
|
79
|
-
[K in keyof
|
|
80
|
-
}
|
|
86
|
+
[K in keyof ${DB_GENERATED_SCHEMA_NAME}]: ${DB_GENERATED_SCHEMA_NAME}[K]["columns"];
|
|
87
|
+
};${clientSchemas ? "\n" + getClientDBGeneratedSchemas(clientSchemas, tablesOrViews, config) : ""}
|
|
81
88
|
`;
|
|
82
89
|
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getRawColumns } from "../DboBuilder/getColumns";
|
|
2
|
+
import { getRawInfo } from "../DboBuilder/ViewHandler/getRawInfo";
|
|
3
|
+
import { getPublishedTableNames } from "../PublishParser/getPublishedTableNames";
|
|
4
|
+
import type { PublishObject, PublishParser } from "../PublishParser/PublishParser";
|
|
5
|
+
import type { ClientSchemaProfiles } from "./getClientDBGeneratedSchemas";
|
|
6
|
+
|
|
7
|
+
export const getPublishSchemas = async (
|
|
8
|
+
publishParser: PublishParser,
|
|
9
|
+
): Promise<ClientSchemaProfiles | undefined> => {
|
|
10
|
+
if (!Array.isArray(publishParser.publish)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const entries = publishParser.publish;
|
|
14
|
+
const profiles: ClientSchemaProfiles = Object.fromEntries(
|
|
15
|
+
entries.map(({ name }) => [name, { tableSchema: [] }]),
|
|
16
|
+
);
|
|
17
|
+
const { tablesOrViews = [] } = publishParser.prostgles.dboBuilder;
|
|
18
|
+
for (const { name, publish } of entries) {
|
|
19
|
+
const publishObject: PublishObject =
|
|
20
|
+
publish === "*" ?
|
|
21
|
+
Object.fromEntries(tablesOrViews.map((table) => [table.name, "*"]))
|
|
22
|
+
: (publish ?? {});
|
|
23
|
+
const tableNames = getPublishedTableNames(publishParser, publishObject);
|
|
24
|
+
for (const tableName of tableNames) {
|
|
25
|
+
const rules = await publishParser.getTableRules(
|
|
26
|
+
{ tableName, clientReq: undefined },
|
|
27
|
+
undefined,
|
|
28
|
+
undefined,
|
|
29
|
+
publishObject,
|
|
30
|
+
);
|
|
31
|
+
if (!rules || !Object.values(rules).some(Boolean)) continue;
|
|
32
|
+
const table = publishParser.dbo[tableName]!;
|
|
33
|
+
profiles[name]!.tableSchema.push({
|
|
34
|
+
...getRawInfo.call(table, undefined, rules),
|
|
35
|
+
name: tableName,
|
|
36
|
+
columns: await getRawColumns.call(table, undefined, undefined, rules),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return profiles;
|
|
41
|
+
};
|
|
@@ -35,6 +35,7 @@ import { prepareShortestJoinPaths } from "./joins/prepareShortestJoinPaths";
|
|
|
35
35
|
import { cacheDBTypes, runSQL } from "./runSql/runSQL";
|
|
36
36
|
import { getDetailedFieldInfo, type getDbTypes } from "./runSql/runSqlUtils";
|
|
37
37
|
import { getTablesForSchemaPostgresSQL } from "./schema/getTablesForSchemaPostgresSQL";
|
|
38
|
+
import { getPublishSchemas } from "../DBSchemaBuilder/getPublishSchemas";
|
|
38
39
|
|
|
39
40
|
export * from "./DboBuilderTypes";
|
|
40
41
|
export * from "./dboBuilderUtils";
|
|
@@ -208,8 +209,8 @@ export class DboBuilder {
|
|
|
208
209
|
return this.shortestJoinPaths;
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
prepareShortestJoinPaths =
|
|
212
|
-
const { joins, shortestJoinPaths, joinGraph } =
|
|
212
|
+
prepareShortestJoinPaths = () => {
|
|
213
|
+
const { joins, shortestJoinPaths, joinGraph } = prepareShortestJoinPaths(this);
|
|
213
214
|
this.joinGraph = joinGraph;
|
|
214
215
|
this.joins = joins;
|
|
215
216
|
this.shortestJoinPaths = shortestJoinPaths;
|
|
@@ -276,7 +277,7 @@ export class DboBuilder {
|
|
|
276
277
|
this.prostgles.dbForSchema!,
|
|
277
278
|
this.prostgles.opts.schemaFilter,
|
|
278
279
|
);
|
|
279
|
-
|
|
280
|
+
this.prepareShortestJoinPaths();
|
|
280
281
|
|
|
281
282
|
this.dbo = {};
|
|
282
283
|
this.tablesOrViews.map((tov) => {
|
|
@@ -349,7 +350,7 @@ export class DboBuilder {
|
|
|
349
350
|
}
|
|
350
351
|
return this.tablesOrViews;
|
|
351
352
|
};
|
|
352
|
-
getTsDefinitions =
|
|
353
|
+
getTsDefinitions = async ({
|
|
353
354
|
excludeFunctions,
|
|
354
355
|
extraTables = [],
|
|
355
356
|
ddlWithRollback,
|
|
@@ -362,12 +363,13 @@ export class DboBuilder {
|
|
|
362
363
|
* This is useful for generating an updated TypeScript schema after running a migration SQL file, for example.
|
|
363
364
|
* Note that this will be run within a transaction that is rolled back, so it SHOULD not affect the actual database schema.
|
|
364
365
|
*/
|
|
365
|
-
ddlWithRollback?:
|
|
366
|
-
} = {}):
|
|
367
|
-
|
|
366
|
+
ddlWithRollback?: string;
|
|
367
|
+
} = {}): Promise<{ tsSchema: string; tablesOrViews: TableSchema[] }> => {
|
|
368
|
+
const clientSchemas = this.publishParser && (await getPublishSchemas(this.publishParser));
|
|
368
369
|
const getSchema = (tablesOrViews: TableSchema[]) => {
|
|
369
370
|
const tableTsDefinitions = getDBGeneratedSchema({
|
|
370
371
|
config: this.prostgles.mergedTableConfig.tableConfig,
|
|
372
|
+
clientSchemas,
|
|
371
373
|
tablesOrViews: [
|
|
372
374
|
...tablesOrViews,
|
|
373
375
|
...extraTables.filter(
|
|
@@ -386,26 +388,17 @@ export class DboBuilder {
|
|
|
386
388
|
return { tsSchema, tablesOrViews };
|
|
387
389
|
};
|
|
388
390
|
if (ddlWithRollback) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
.then((res) => {
|
|
395
|
-
const tablesOrViews = res.result;
|
|
396
|
-
resolve(getSchema(tablesOrViews));
|
|
397
|
-
})
|
|
398
|
-
.catch(reject);
|
|
399
|
-
}) as DDL extends string ? Promise<{ tsSchema: string; tablesOrViews: TableSchema[] }>
|
|
400
|
-
: { tsSchema: string; tablesOrViews: TableSchema[] };
|
|
391
|
+
const { result } = await getTablesForSchemaPostgresSQL(this, {
|
|
392
|
+
schemaFilter: this.prostgles.opts.schemaFilter,
|
|
393
|
+
ddlWithRollback,
|
|
394
|
+
});
|
|
395
|
+
return getSchema(result);
|
|
401
396
|
}
|
|
402
397
|
const tablesOrViews = this.tablesOrViews;
|
|
403
398
|
if (!tablesOrViews) {
|
|
404
399
|
throw new Error("Unexpected error: tablesOrViews is undefined");
|
|
405
400
|
}
|
|
406
|
-
return getSchema(tablesOrViews)
|
|
407
|
-
Promise<{ tsSchema: string; tablesOrViews: TableSchema[] }>
|
|
408
|
-
: { tsSchema: string; tablesOrViews: TableSchema[] };
|
|
401
|
+
return getSchema(tablesOrViews);
|
|
409
402
|
};
|
|
410
403
|
|
|
411
404
|
getShortestJoinPath = (
|
package/lib/Prostgles.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DB_GENERATED_SCHEMA_NAME } from "./DBSchemaBuilder/constants";
|
|
1
2
|
import type pgPromise from "pg-promise";
|
|
2
3
|
import { AuthHandler } from "./Auth/AuthHandler";
|
|
3
4
|
import type { SessionUser } from "./Auth/AuthTypes";
|
|
@@ -21,7 +22,7 @@ export { applyTableConfig } from "./TableConfig/applyTableConfig";
|
|
|
21
22
|
|
|
22
23
|
import { CHANNELS, tryCatchV2 } from "prostgles-types";
|
|
23
24
|
import type { DBEventsManager } from "./DBEventsManager";
|
|
24
|
-
import
|
|
25
|
+
import { PublishParser } from "./PublishParser/PublishParser";
|
|
25
26
|
import { pushSocketSchema } from "./WebsocketAPI/pushSocketSchema";
|
|
26
27
|
|
|
27
28
|
export type DB = pgPromise.IDatabase<{}, pg.IClient>;
|
|
@@ -229,7 +230,7 @@ export class Prostgles {
|
|
|
229
230
|
}
|
|
230
231
|
|
|
231
232
|
getTSFileName() {
|
|
232
|
-
const fileName =
|
|
233
|
+
const fileName = `${DB_GENERATED_SCHEMA_NAME}.ts`;
|
|
233
234
|
const _dir = this.opts.tsGeneratedTypesDir || "";
|
|
234
235
|
const dir = _dir.endsWith("/") ? _dir : `${_dir}/`;
|
|
235
236
|
const fullPath = dir + fileName;
|
|
@@ -240,10 +241,10 @@ export class Prostgles {
|
|
|
240
241
|
* Will write the Schema Typescript definitions to file (tsGeneratedTypesDir)
|
|
241
242
|
* force is used for hotReloadMode to trigger a restart
|
|
242
243
|
*/
|
|
243
|
-
writeDBSchema(force = false) {
|
|
244
|
+
async writeDBSchema(force = false) {
|
|
244
245
|
if (this.opts.tsGeneratedTypesDir) {
|
|
246
|
+
const { tsSchema: fileContent } = await this.dboBuilder.getTsDefinitions();
|
|
245
247
|
const { fullPath, fileName } = this.getTSFileName();
|
|
246
|
-
const { tsSchema: fileContent } = this.dboBuilder.getTsDefinitions();
|
|
247
248
|
fs.mkdirSync(dirname(fullPath), { recursive: true });
|
|
248
249
|
|
|
249
250
|
const existingContent =
|
|
@@ -348,6 +349,11 @@ export class Prostgles {
|
|
|
348
349
|
this.restApi = this.opts.restApi && new RestApi({ prostgles: this, ...this.opts.restApi });
|
|
349
350
|
};
|
|
350
351
|
|
|
352
|
+
initPublishParser = () => {
|
|
353
|
+
this.publishParser = new PublishParser(this);
|
|
354
|
+
this.dboBuilder.publishParser = this.publishParser;
|
|
355
|
+
};
|
|
356
|
+
|
|
351
357
|
initAuthHandler = () => {
|
|
352
358
|
this.authHandler.destroy();
|
|
353
359
|
this.authHandler = new AuthHandler(this);
|
|
@@ -25,9 +25,12 @@ import {
|
|
|
25
25
|
type PermissionScope,
|
|
26
26
|
type PublishObject,
|
|
27
27
|
} from "./publishTypesAndUtils";
|
|
28
|
+
import { validatePublishProfiles } from "./validatePublishProfiles";
|
|
28
29
|
|
|
29
30
|
export class PublishParser {
|
|
30
|
-
publish:
|
|
31
|
+
publish:
|
|
32
|
+
| Exclude<ProstglesInitOptions<void, SessionUser, any>["publish"], unknown[]>
|
|
33
|
+
| ReturnType<typeof validatePublishProfiles>;
|
|
31
34
|
publishRawSQL?: any;
|
|
32
35
|
dbo: DBHandlerServer;
|
|
33
36
|
db: DB;
|
|
@@ -35,7 +38,8 @@ export class PublishParser {
|
|
|
35
38
|
|
|
36
39
|
constructor(prostgles: Prostgles) {
|
|
37
40
|
this.prostgles = prostgles;
|
|
38
|
-
|
|
41
|
+
const { publish } = prostgles.opts;
|
|
42
|
+
this.publish = Array.isArray(publish) ? validatePublishProfiles(publish) : publish;
|
|
39
43
|
|
|
40
44
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
41
45
|
this.publishRawSQL = prostgles.opts.publishRawSQL;
|
|
@@ -119,7 +123,7 @@ export class PublishParser {
|
|
|
119
123
|
const { clientDb } = await publishParams.getClientDBHandlers(undefined);
|
|
120
124
|
const { clientInfo, clientReq, tables } = publishParams;
|
|
121
125
|
const restrictedCtx: RestrictedFunctionContext<void, SessionUser, unknown> = {
|
|
122
|
-
dbo: clientDb
|
|
126
|
+
dbo: clientDb,
|
|
123
127
|
user,
|
|
124
128
|
clientInfo,
|
|
125
129
|
clientReq,
|
|
@@ -146,7 +150,17 @@ export class PublishParser {
|
|
|
146
150
|
clientInfo: AuthResultWithSID | undefined,
|
|
147
151
|
): Promise<PublishObject | undefined> {
|
|
148
152
|
const publishParams = await this.getPublishParams(clientReq, clientInfo);
|
|
149
|
-
|
|
153
|
+
|
|
154
|
+
const publish = await (() => {
|
|
155
|
+
if (Array.isArray(this.publish)) {
|
|
156
|
+
const { user } = publishParams;
|
|
157
|
+
if (!user) return undefined;
|
|
158
|
+
return this.publish.find((publishRule) => publishRule.userTypes.includes(user.type))
|
|
159
|
+
?.publish;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return applyParamsIfFunc(this.publish, publishParams);
|
|
163
|
+
})();
|
|
150
164
|
|
|
151
165
|
if (publish === "*") {
|
|
152
166
|
const publish: PublishObject = {};
|
|
@@ -271,13 +285,18 @@ export class PublishParser {
|
|
|
271
285
|
args: DboTable,
|
|
272
286
|
clientInfo: AuthResultWithSID | undefined,
|
|
273
287
|
scope: PermissionScope | undefined,
|
|
288
|
+
overriddenPublish?: PublishObject,
|
|
274
289
|
): Promise<ParsedTableRule | undefined> {
|
|
275
290
|
const { tableName } = args;
|
|
276
291
|
const tableHandler = this.dbo[tableName];
|
|
277
292
|
if (!tableHandler) {
|
|
278
293
|
throw "INTERNAL ERROR: table handler not found for " + args.tableName;
|
|
279
294
|
}
|
|
280
|
-
const fileTablePublishRules = await this.getTableRulesWithoutFileTable(
|
|
295
|
+
const fileTablePublishRules = await this.getTableRulesWithoutFileTable(
|
|
296
|
+
args,
|
|
297
|
+
clientInfo,
|
|
298
|
+
overriddenPublish,
|
|
299
|
+
);
|
|
281
300
|
if (this.dbo[args.tableName]?.is_media) {
|
|
282
301
|
const { rules: fileTableRules } = await getFileTableRules.bind(this)(
|
|
283
302
|
args.tableName,
|
|
@@ -285,6 +304,7 @@ export class PublishParser {
|
|
|
285
304
|
args.clientReq,
|
|
286
305
|
clientInfo,
|
|
287
306
|
scope,
|
|
307
|
+
overriddenPublish,
|
|
288
308
|
);
|
|
289
309
|
return applyScopeToTableRules(
|
|
290
310
|
tableName,
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
SQLHandler,
|
|
9
9
|
} from "prostgles-types";
|
|
10
10
|
import type { SessionUser } from "../Auth/AuthTypes";
|
|
11
|
-
import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
|
|
11
|
+
import type { DBOFullyTyped, DBOFullyTypedClient } from "../DBSchemaBuilder/DBSchemaBuilder";
|
|
12
12
|
import type { DB } from "../initProstgles";
|
|
13
13
|
import type { PublishParams } from "./publishTypesAndUtils";
|
|
14
14
|
|
|
@@ -17,7 +17,6 @@ type FunctionContextBase<S, SUser extends SessionUser, Context> = Pick<
|
|
|
17
17
|
"tables" | "clientReq" | "clientInfo"
|
|
18
18
|
> & {
|
|
19
19
|
context: Context;
|
|
20
|
-
dbo: DBOFullyTyped<S>;
|
|
21
20
|
user: S extends DBSchema ?
|
|
22
21
|
S["users"]["columns"] extends AnyObject ?
|
|
23
22
|
Required<S["users"]["columns"]>
|
|
@@ -29,13 +28,16 @@ export type RestrictedFunctionContext<
|
|
|
29
28
|
S = void,
|
|
30
29
|
SUser extends SessionUser = SessionUser,
|
|
31
30
|
Context = undefined,
|
|
32
|
-
> = FunctionContextBase<S, SUser, Context
|
|
31
|
+
> = FunctionContextBase<S, SUser, Context> & {
|
|
32
|
+
dbo: DBOFullyTypedClient<S>;
|
|
33
|
+
};
|
|
33
34
|
|
|
34
35
|
export type UnrestrictedFunctionContext<
|
|
35
36
|
S = void,
|
|
36
37
|
SUser extends SessionUser = SessionUser,
|
|
37
38
|
Context = undefined,
|
|
38
39
|
> = FunctionContextBase<S, SUser, Context> & {
|
|
40
|
+
dbo: DBOFullyTyped<S>;
|
|
39
41
|
db: DB;
|
|
40
42
|
sql: SQLHandler;
|
|
41
43
|
getClientDBHandlers: PublishParams<S, SUser>["getClientDBHandlers"];
|
|
@@ -3,7 +3,7 @@ import { includes, isDefined } from "prostgles-types";
|
|
|
3
3
|
import type { AuthClientRequest, AuthResultWithSID } from "../Auth/AuthTypes";
|
|
4
4
|
import { parseFieldFilter } from "../DboBuilder/ViewHandler/parseFieldFilter";
|
|
5
5
|
import type { PublishParser } from "./PublishParser";
|
|
6
|
-
import type { ParsedPublishTable, UpdateRule } from "./publishTypesAndUtils";
|
|
6
|
+
import type { ParsedPublishTable, PublishObject, UpdateRule } from "./publishTypesAndUtils";
|
|
7
7
|
import type { LocalParams } from "../DboBuilder/DboBuilder";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -21,6 +21,7 @@ export async function getFileTableRules(
|
|
|
21
21
|
clientReq: AuthClientRequest | undefined,
|
|
22
22
|
clientInfo: AuthResultWithSID | undefined,
|
|
23
23
|
scope: LocalParams["scope"],
|
|
24
|
+
overriddenPublish?: PublishObject,
|
|
24
25
|
) {
|
|
25
26
|
const forcedDeleteFilters: FullFilter<AnyObject, void>[] = [];
|
|
26
27
|
const forcedSelectFilters: FullFilter<AnyObject, void>[] = [];
|
|
@@ -42,7 +43,7 @@ export async function getFileTableRules(
|
|
|
42
43
|
.filter(isDefined);
|
|
43
44
|
if (referencedColumns?.length) {
|
|
44
45
|
for (const { tableName, fileColumns, allColumns } of referencedColumns) {
|
|
45
|
-
const tableRules = await this.getTableRules({ clientReq, tableName }, clientInfo, scope);
|
|
46
|
+
const tableRules = await this.getTableRules({ clientReq, tableName }, clientInfo, scope, overriddenPublish);
|
|
46
47
|
if (tableRules) {
|
|
47
48
|
fileColumns.map((column) => {
|
|
48
49
|
const path = [{ table: tableName, on: [{ id: column }] }];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PublishParser } from "./PublishParser";
|
|
2
|
+
import { type PublishObject } from "./PublishParser";
|
|
3
|
+
|
|
4
|
+
export const getPublishedTableNames = (
|
|
5
|
+
publishParserInstance: PublishParser,
|
|
6
|
+
publishObject: PublishObject,
|
|
7
|
+
) => {
|
|
8
|
+
const txKey = !publishParserInstance.prostgles.opts.transactions ? "" : "tx";
|
|
9
|
+
const tableNames = Object.keys(publishObject).filter((k) => !txKey || txKey !== k);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Add file table to the list of published tables if it's referenced by other published tables.
|
|
13
|
+
* Access to the file table is controlled through the publish rules of the tables referencing it.
|
|
14
|
+
*/
|
|
15
|
+
const fileTableName = publishParserInstance.prostgles.opts.fileTable?.tableName;
|
|
16
|
+
if (
|
|
17
|
+
fileTableName &&
|
|
18
|
+
publishParserInstance.dbo[fileTableName]?.is_media &&
|
|
19
|
+
!tableNames.includes(fileTableName)
|
|
20
|
+
) {
|
|
21
|
+
const isReferenced = publishParserInstance.prostgles.dboBuilder.tablesOrViews?.some((t) =>
|
|
22
|
+
t.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName)),
|
|
23
|
+
);
|
|
24
|
+
if (isReferenced) {
|
|
25
|
+
tableNames.unshift(fileTableName);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return tableNames;
|
|
29
|
+
};
|
|
@@ -4,6 +4,7 @@ import type { AuthClientRequest, AuthResultWithSID } from "../Auth/AuthTypes";
|
|
|
4
4
|
import type { PublishParser } from "./PublishParser";
|
|
5
5
|
import { type PermissionScope, type PublishObject } from "./PublishParser";
|
|
6
6
|
import { getDBSchemaTable } from "./getDBSchemaTable";
|
|
7
|
+
import { getPublishedTableNames } from "./getPublishedTableNames";
|
|
7
8
|
|
|
8
9
|
type Args = AuthClientRequest & {
|
|
9
10
|
userData: AuthResultWithSID | undefined;
|
|
@@ -19,8 +20,6 @@ export async function getSchemaFromPublish(
|
|
|
19
20
|
const tableSchemaErrors: TableSchemaErrors = {};
|
|
20
21
|
const tables: DBSchemaTable[] = [];
|
|
21
22
|
|
|
22
|
-
const txKey = !this.prostgles.opts.transactions ? "" : "tx";
|
|
23
|
-
|
|
24
23
|
try {
|
|
25
24
|
/* Publish tables and views based on socket */
|
|
26
25
|
const clientInfo =
|
|
@@ -39,21 +38,7 @@ export async function getSchemaFromPublish(
|
|
|
39
38
|
if (!publish || !Object.keys(publish).length) {
|
|
40
39
|
return { tables, tableSchemaErrors };
|
|
41
40
|
}
|
|
42
|
-
const tableNames =
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Add file table to the list of published tables if it's referenced by other published tables.
|
|
46
|
-
* Access to the file table is controlled through the publish rules of the tables referencing it.
|
|
47
|
-
*/
|
|
48
|
-
const fileTableName = this.prostgles.opts.fileTable?.tableName;
|
|
49
|
-
if (fileTableName && this.dbo[fileTableName]?.is_media && !tableNames.includes(fileTableName)) {
|
|
50
|
-
const isReferenced = this.prostgles.dboBuilder.tablesOrViews?.some((t) =>
|
|
51
|
-
t.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName)),
|
|
52
|
-
);
|
|
53
|
-
if (isReferenced) {
|
|
54
|
-
tableNames.unshift(fileTableName);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
41
|
+
const tableNames = getPublishedTableNames(this, publish);
|
|
57
42
|
|
|
58
43
|
await Promise.all(
|
|
59
44
|
tableNames.map(async (tableName) => {
|
|
@@ -62,7 +62,7 @@ export type ValidateBeforeRowArgsCommon<R = AnyObject, DBX = DBHandlerServer> =
|
|
|
62
62
|
data: Partial<R>;
|
|
63
63
|
filter: AnyObject | undefined;
|
|
64
64
|
};
|
|
65
|
-
export type ValidateRowArgsCommon<R = AnyObject, DBX = DBHandlerServer> = {
|
|
65
|
+
export type ValidateRowArgsCommon<R = AnyObject, DBX = DBHandlerServer, InputDataType = R> = {
|
|
66
66
|
row: R;
|
|
67
67
|
dbx: DBX;
|
|
68
68
|
tx: pgPromise.ITask<{}> | DB;
|
|
@@ -73,11 +73,12 @@ export type ValidateRowArgsCommon<R = AnyObject, DBX = DBHandlerServer> = {
|
|
|
73
73
|
}
|
|
74
74
|
| {
|
|
75
75
|
command: "insert";
|
|
76
|
-
|
|
76
|
+
/** The whole input, including all rows for a bulk insert. */
|
|
77
|
+
data: Partial<InputDataType> | Partial<InputDataType>[];
|
|
77
78
|
}
|
|
78
79
|
| {
|
|
79
80
|
command: "update";
|
|
80
|
-
data: Partial<
|
|
81
|
+
data: Partial<InputDataType>;
|
|
81
82
|
}
|
|
82
83
|
);
|
|
83
84
|
|
|
@@ -113,14 +114,14 @@ export type TransactionCallbacks<DBO = DBHandlerServer> = {
|
|
|
113
114
|
onRollback: OnCommit<DBO>;
|
|
114
115
|
};
|
|
115
116
|
|
|
116
|
-
export type AfterEachTsTrigger<R, DBX, Context = undefined> = {
|
|
117
|
+
export type AfterEachTsTrigger<R, DBX, Context = undefined, InputDataType = R> = {
|
|
117
118
|
commands: Partial<Record<"insert" | "update" | "delete", 1>>;
|
|
118
119
|
/**
|
|
119
120
|
* Will only run this trigger if the insert/update provides non null values for these fields.
|
|
120
121
|
*/
|
|
121
122
|
changedFields?: (keyof R)[];
|
|
122
123
|
validate: (
|
|
123
|
-
params: ValidateRowArgsCommon<R, DBX> &
|
|
124
|
+
params: ValidateRowArgsCommon<R, DBX, InputDataType> &
|
|
124
125
|
TransactionCallbacks<DBX> & {
|
|
125
126
|
localParams: undefined | LocalParams;
|
|
126
127
|
context: Context;
|
|
@@ -556,6 +557,13 @@ export type ParsedPublishTables = {
|
|
|
556
557
|
|
|
557
558
|
type PublishAllOrNothingRoot = Exclude<PublishAllOrNothing, boolean>;
|
|
558
559
|
export type PublishedResult<Schema = void> = PublishAllOrNothingRoot | PublishFullyTyped<Schema>;
|
|
560
|
+
export type PublishProfile<Schema = void> = {
|
|
561
|
+
/** Exported schema type name; defaults to Publish1Schema, Publish2Schema, etc. */
|
|
562
|
+
name?: string;
|
|
563
|
+
userTypes: string[];
|
|
564
|
+
publish: PublishedResult<Schema>;
|
|
565
|
+
};
|
|
559
566
|
export type Publish<Schema = void, SUser extends SessionUser = SessionUser> =
|
|
567
|
+
| PublishProfile<Schema>[]
|
|
560
568
|
| PublishedResult<Schema>
|
|
561
569
|
| ((params: PublishParams<Schema, SUser>) => Awaitable<PublishedResult<Schema>>);
|