prostgles-server 4.2.624 → 4.2.626

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.
Files changed (223) hide show
  1. package/dist/Audit/AuditTable.d.ts +4 -2
  2. package/dist/Audit/AuditTable.d.ts.map +1 -1
  3. package/dist/Audit/AuditTable.js +3 -2
  4. package/dist/Audit/AuditTable.js.map +1 -1
  5. package/dist/Audit/getAuditTableRules.d.ts +7 -0
  6. package/dist/Audit/getAuditTableRules.d.ts.map +1 -0
  7. package/dist/Audit/getAuditTableRules.js +191 -0
  8. package/dist/Audit/getAuditTableRules.js.map +1 -0
  9. package/dist/Audit/getAuditTriggerConfig.d.ts.map +1 -1
  10. package/dist/Audit/getAuditTriggerConfig.js +14 -1
  11. package/dist/Audit/getAuditTriggerConfig.js.map +1 -1
  12. package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.d.ts.map +1 -1
  13. package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js +7 -1
  14. package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js.map +1 -1
  15. package/dist/DBSchemaBuilder/getDBGeneratedSchema.d.ts.map +1 -1
  16. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js +1 -2
  17. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js.map +1 -1
  18. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts +10 -5
  19. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
  20. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +90 -71
  21. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
  22. package/dist/DboBuilder/QueryBuilder/getJoinQuery.d.ts.map +1 -1
  23. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js +3 -2
  24. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js.map +1 -1
  25. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts +2 -2
  26. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts.map +1 -1
  27. package/dist/DboBuilder/QueryBuilder/getNewQuery.js +53 -116
  28. package/dist/DboBuilder/QueryBuilder/getNewQuery.js.map +1 -1
  29. package/dist/DboBuilder/QueryBuilder/getQuerySource.d.ts +18 -0
  30. package/dist/DboBuilder/QueryBuilder/getQuerySource.d.ts.map +1 -0
  31. package/dist/DboBuilder/QueryBuilder/getQuerySource.js +29 -0
  32. package/dist/DboBuilder/QueryBuilder/getQuerySource.js.map +1 -0
  33. package/dist/DboBuilder/QueryBuilder/getSelectQuery.d.ts.map +1 -1
  34. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js +6 -2
  35. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js.map +1 -1
  36. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.d.ts +13 -0
  37. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.d.ts.map +1 -0
  38. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js +57 -0
  39. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js.map +1 -0
  40. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  41. package/dist/DboBuilder/TableHandler/TableHandler.js +2 -1
  42. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  43. package/dist/DboBuilder/TableHandler/delete.d.ts.map +1 -1
  44. package/dist/DboBuilder/TableHandler/delete.js +2 -1
  45. package/dist/DboBuilder/TableHandler/delete.js.map +1 -1
  46. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.d.ts +3 -1
  47. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.d.ts.map +1 -1
  48. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js +19 -5
  49. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js.map +1 -1
  50. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.d.ts.map +1 -1
  51. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js +2 -1
  52. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js.map +1 -1
  53. package/dist/DboBuilder/TableHandler/update.d.ts.map +1 -1
  54. package/dist/DboBuilder/TableHandler/update.js +2 -1
  55. package/dist/DboBuilder/TableHandler/update.js.map +1 -1
  56. package/dist/DboBuilder/TableHandler/updateFile.d.ts +2 -39
  57. package/dist/DboBuilder/TableHandler/updateFile.d.ts.map +1 -1
  58. package/dist/DboBuilder/TableHandler/updateFile.js +1 -0
  59. package/dist/DboBuilder/TableHandler/updateFile.js.map +1 -1
  60. package/dist/DboBuilder/TableHandler/uploadFile.d.ts +2 -1
  61. package/dist/DboBuilder/TableHandler/uploadFile.d.ts.map +1 -1
  62. package/dist/DboBuilder/TableHandler/uploadFile.js +2 -1
  63. package/dist/DboBuilder/TableHandler/uploadFile.js.map +1 -1
  64. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +6 -16
  65. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
  66. package/dist/DboBuilder/ViewHandler/ViewHandler.js +2 -7
  67. package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
  68. package/dist/DboBuilder/ViewHandler/find.d.ts.map +1 -1
  69. package/dist/DboBuilder/ViewHandler/find.js +1 -1
  70. package/dist/DboBuilder/ViewHandler/find.js.map +1 -1
  71. package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts +1 -1
  72. package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts.map +1 -1
  73. package/dist/DboBuilder/ViewHandler/getExistsCondition.js +24 -13
  74. package/dist/DboBuilder/ViewHandler/getExistsCondition.js.map +1 -1
  75. package/dist/DboBuilder/ViewHandler/getRawInfo.d.ts.map +1 -1
  76. package/dist/DboBuilder/ViewHandler/getRawInfo.js +6 -2
  77. package/dist/DboBuilder/ViewHandler/getRawInfo.js.map +1 -1
  78. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts +4 -1
  79. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts.map +1 -1
  80. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js +20 -14
  81. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js.map +1 -1
  82. package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts +7 -3
  83. package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts.map +1 -1
  84. package/dist/DboBuilder/ViewHandler/prepareWhere.js +30 -23
  85. package/dist/DboBuilder/ViewHandler/prepareWhere.js.map +1 -1
  86. package/dist/DboBuilder/getColumns.d.ts.map +1 -1
  87. package/dist/DboBuilder/getColumns.js +3 -0
  88. package/dist/DboBuilder/getColumns.js.map +1 -1
  89. package/dist/DboBuilder/getCondition.d.ts +2 -1
  90. package/dist/DboBuilder/getCondition.d.ts.map +1 -1
  91. package/dist/DboBuilder/getCondition.js +9 -8
  92. package/dist/DboBuilder/getCondition.js.map +1 -1
  93. package/dist/DboBuilder/getSubscribeRelatedTables.d.ts.map +1 -1
  94. package/dist/DboBuilder/getSubscribeRelatedTables.js +3 -2
  95. package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
  96. package/dist/DboBuilder/parseUpdateRules.d.ts.map +1 -1
  97. package/dist/DboBuilder/parseUpdateRules.js +3 -2
  98. package/dist/DboBuilder/parseUpdateRules.js.map +1 -1
  99. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts +2 -2
  100. package/dist/Prostgles.d.ts.map +1 -1
  101. package/dist/Prostgles.js +2 -0
  102. package/dist/Prostgles.js.map +1 -1
  103. package/dist/ProstglesContext.spec.js +25 -0
  104. package/dist/ProstglesContext.spec.js.map +1 -1
  105. package/dist/ProstglesTypes.d.ts +10 -0
  106. package/dist/ProstglesTypes.d.ts.map +1 -1
  107. package/dist/ProstglesTypes.js.map +1 -1
  108. package/dist/PubSubManager/PubSubManager.d.ts +1 -1
  109. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  110. package/dist/PublishParser/PublishParser.js +22 -4
  111. package/dist/PublishParser/PublishParser.js.map +1 -1
  112. package/dist/PublishParser/applyScopeToTableRules.d.ts +0 -1
  113. package/dist/PublishParser/applyScopeToTableRules.d.ts.map +1 -1
  114. package/dist/PublishParser/applyScopeToTableRules.js +3 -7
  115. package/dist/PublishParser/applyScopeToTableRules.js.map +1 -1
  116. package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
  117. package/dist/PublishParser/getFileTableRules.js +4 -1
  118. package/dist/PublishParser/getFileTableRules.js.map +1 -1
  119. package/dist/PublishParser/getFileVersionTableRules.d.ts +7 -0
  120. package/dist/PublishParser/getFileVersionTableRules.d.ts.map +1 -0
  121. package/dist/PublishParser/getFileVersionTableRules.js +77 -0
  122. package/dist/PublishParser/getFileVersionTableRules.js.map +1 -0
  123. package/dist/PublishParser/getFileVersionTableRules.spec.d.ts +2 -0
  124. package/dist/PublishParser/getFileVersionTableRules.spec.d.ts.map +1 -0
  125. package/dist/PublishParser/getFileVersionTableRules.spec.js +50 -0
  126. package/dist/PublishParser/getFileVersionTableRules.spec.js.map +1 -0
  127. package/dist/PublishParser/getPublishedTableNames.d.ts.map +1 -1
  128. package/dist/PublishParser/getPublishedTableNames.js +24 -1
  129. package/dist/PublishParser/getPublishedTableNames.js.map +1 -1
  130. package/dist/PublishParser/publishTypesAndUtils.d.ts +0 -4
  131. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  132. package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
  133. package/dist/StorageClient/deleteUnreferencedFile.d.ts.map +1 -1
  134. package/dist/StorageClient/deleteUnreferencedFile.js +17 -1
  135. package/dist/StorageClient/deleteUnreferencedFile.js.map +1 -1
  136. package/dist/StorageClient/fileTableDefinitions.d.ts +54 -0
  137. package/dist/StorageClient/fileTableDefinitions.d.ts.map +1 -0
  138. package/dist/StorageClient/fileTableDefinitions.js +38 -0
  139. package/dist/StorageClient/fileTableDefinitions.js.map +1 -0
  140. package/dist/StorageClient/fileVersionUtils.d.ts +18 -0
  141. package/dist/StorageClient/fileVersionUtils.d.ts.map +1 -0
  142. package/dist/StorageClient/fileVersionUtils.js +22 -0
  143. package/dist/StorageClient/fileVersionUtils.js.map +1 -0
  144. package/dist/StorageClient/getFileStorageKey.d.ts +3 -1
  145. package/dist/StorageClient/getFileStorageKey.d.ts.map +1 -1
  146. package/dist/StorageClient/getFileStorageKey.js +9 -1
  147. package/dist/StorageClient/getFileStorageKey.js.map +1 -1
  148. package/dist/StorageClient/getFileTableConfig.d.ts +1 -23
  149. package/dist/StorageClient/getFileTableConfig.d.ts.map +1 -1
  150. package/dist/StorageClient/getFileTableConfig.js +63 -25
  151. package/dist/StorageClient/getFileTableConfig.js.map +1 -1
  152. package/dist/StorageClient/getFileTableConfig.spec.js +6 -1
  153. package/dist/StorageClient/getFileTableConfig.spec.js.map +1 -1
  154. package/dist/StorageClient/saveFileVersion.d.ts +7 -0
  155. package/dist/StorageClient/saveFileVersion.d.ts.map +1 -0
  156. package/dist/StorageClient/saveFileVersion.js +71 -0
  157. package/dist/StorageClient/saveFileVersion.js.map +1 -0
  158. package/dist/StorageClient/setupFileServeHandler.d.ts.map +1 -1
  159. package/dist/StorageClient/setupFileServeHandler.js +38 -21
  160. package/dist/StorageClient/setupFileServeHandler.js.map +1 -1
  161. package/dist/TableConfig/TableRowFromColumnDefinitions.d.ts +11 -4
  162. package/dist/TableConfig/TableRowFromColumnDefinitions.d.ts.map +1 -1
  163. package/dist/TableConfig/getColumnSQLDefinitionQuery.d.ts.map +1 -1
  164. package/dist/TableConfig/getColumnSQLDefinitionQuery.js +1 -2
  165. package/dist/TableConfig/getColumnSQLDefinitionQuery.js.map +1 -1
  166. package/dist/TableConfig/initTableConfig.d.ts.map +1 -1
  167. package/dist/TableConfig/initTableConfig.js +9 -6
  168. package/dist/TableConfig/initTableConfig.js.map +1 -1
  169. package/dist/index.d.ts +2 -2
  170. package/dist/index.d.ts.map +1 -1
  171. package/dist/index.js +2 -1
  172. package/dist/index.js.map +1 -1
  173. package/lib/Audit/AuditTable.ts +8 -4
  174. package/lib/Audit/getAuditTableRules.ts +292 -0
  175. package/lib/Audit/getAuditTriggerConfig.ts +14 -1
  176. package/lib/DBSchemaBuilder/getClientDBGeneratedSchemas.ts +9 -1
  177. package/lib/DBSchemaBuilder/getDBGeneratedSchema.ts +1 -2
  178. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +118 -90
  179. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +3 -2
  180. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +111 -194
  181. package/lib/DboBuilder/QueryBuilder/getQuerySource.ts +55 -0
  182. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +8 -2
  183. package/lib/DboBuilder/QueryBuilder/parseJoinSelect.ts +73 -0
  184. package/lib/DboBuilder/TableHandler/TableHandler.ts +3 -6
  185. package/lib/DboBuilder/TableHandler/delete.ts +2 -1
  186. package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +31 -5
  187. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +2 -1
  188. package/lib/DboBuilder/TableHandler/update.ts +2 -1
  189. package/lib/DboBuilder/TableHandler/updateFile.ts +1 -0
  190. package/lib/DboBuilder/TableHandler/uploadFile.ts +3 -0
  191. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +6 -12
  192. package/lib/DboBuilder/ViewHandler/find.ts +0 -1
  193. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +35 -28
  194. package/lib/DboBuilder/ViewHandler/getRawInfo.ts +6 -2
  195. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +22 -14
  196. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +48 -27
  197. package/lib/DboBuilder/getColumns.ts +2 -0
  198. package/lib/DboBuilder/getCondition.ts +11 -10
  199. package/lib/DboBuilder/getSubscribeRelatedTables.ts +3 -2
  200. package/lib/DboBuilder/parseUpdateRules.ts +3 -2
  201. package/lib/Prostgles.ts +1 -0
  202. package/lib/ProstglesContext.spec.ts +30 -0
  203. package/lib/ProstglesTypes.ts +11 -0
  204. package/lib/PublishParser/PublishParser.ts +47 -4
  205. package/lib/PublishParser/applyScopeToTableRules.ts +1 -7
  206. package/lib/PublishParser/getFileTableRules.ts +7 -1
  207. package/lib/PublishParser/getFileVersionTableRules.spec.ts +57 -0
  208. package/lib/PublishParser/getFileVersionTableRules.ts +106 -0
  209. package/lib/PublishParser/getPublishedTableNames.ts +33 -2
  210. package/lib/PublishParser/publishTypesAndUtils.ts +0 -5
  211. package/lib/StorageClient/deleteUnreferencedFile.ts +20 -2
  212. package/lib/StorageClient/fileTableDefinitions.ts +52 -0
  213. package/lib/StorageClient/fileVersionUtils.ts +37 -0
  214. package/lib/StorageClient/getFileStorageKey.ts +11 -2
  215. package/lib/StorageClient/getFileTableConfig.spec.ts +6 -1
  216. package/lib/StorageClient/getFileTableConfig.ts +85 -30
  217. package/lib/StorageClient/saveFileVersion.ts +82 -0
  218. package/lib/StorageClient/setupFileServeHandler.ts +51 -28
  219. package/lib/TableConfig/TableRowFromColumnDefinitions.ts +37 -13
  220. package/lib/TableConfig/getColumnSQLDefinitionQuery.ts +8 -2
  221. package/lib/TableConfig/initTableConfig.ts +10 -6
  222. package/lib/index.ts +3 -1
  223. package/package.json +1 -1
@@ -6,6 +6,7 @@ import {
6
6
  } from "prostgles-types";
7
7
  import { getClientRequestIPsInfo } from "../Auth/AuthHandler";
8
8
  import type { AuthClientRequest, AuthResultWithSID, SessionUser } from "../Auth/AuthTypes";
9
+ import { getAuditTableRules } from "../Audit/getAuditTableRules";
9
10
  import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
10
11
  import type { DB, DBHandlerServer, Prostgles } from "../Prostgles";
11
12
  import { getClientHandlers } from "../WebsocketAPI/getClientHandlers";
@@ -16,6 +17,8 @@ import type {
16
17
  UnrestrictedFunctionContext,
17
18
  } from "./defineServerFunction";
18
19
  import { getFileTableRules } from "./getFileTableRules";
20
+ import { getFileVersionTableRules } from "./getFileVersionTableRules";
21
+ import { isFileVersionTable } from "../StorageClient/fileVersionUtils";
19
22
  import { getPublishedObjectFromResult } from "./getPublishedObjectFromResult";
20
23
  import { getSchemaFromPublish } from "./getSchemaFromPublish";
21
24
  import { getParsedPublishTable } from "./getParsedPublishTable";
@@ -305,16 +308,56 @@ export class PublishParser {
305
308
  if (!tableHandler) {
306
309
  throw "INTERNAL ERROR: table handler not found for " + tableName;
307
310
  }
308
- const publishRulesExcludingFileTable = await this.getParsedPublishTable({
311
+ const audit = this.prostgles.resolvedAuditConfig;
312
+ const isAuditTable = audit?.tableName === tableName;
313
+ const resolvedPublishObject =
314
+ overriddenPublish ??
315
+ (isAuditTable && clientReq ?
316
+ await this.getPublishObjectForUser(clientReq, clientInfo)
317
+ : undefined);
318
+ const publishRulesExcludingInferredTables = await this.getParsedPublishTable({
309
319
  clientReq,
310
320
  tableName,
311
321
  clientInfo,
312
- resolvedPublishObject: overriddenPublish,
322
+ resolvedPublishObject,
313
323
  });
324
+ if (audit && isAuditTable) {
325
+ const auditTableRules = await getAuditTableRules.bind(this)(
326
+ audit,
327
+ publishRulesExcludingInferredTables,
328
+ clientReq,
329
+ clientInfo,
330
+ scope,
331
+ resolvedPublishObject,
332
+ );
333
+ return applyScopeToTableRules(
334
+ tableName,
335
+ tableHandler,
336
+ parsePublishTableRule(auditTableRules),
337
+ scope,
338
+ );
339
+ }
340
+ const fileConfig = this.prostgles.opts.fileTable;
341
+ if (isFileVersionTable(fileConfig, tableName)) {
342
+ const versionRules = await getFileVersionTableRules.bind(this)(
343
+ fileConfig,
344
+ publishRulesExcludingInferredTables,
345
+ clientReq,
346
+ clientInfo,
347
+ scope,
348
+ overriddenPublish,
349
+ );
350
+ return applyScopeToTableRules(
351
+ tableName,
352
+ tableHandler,
353
+ parsePublishTableRule(versionRules),
354
+ scope,
355
+ );
356
+ }
314
357
  if (this.dbo[tableName]?.is_media) {
315
358
  const { rules: fileTableRules } = await getFileTableRules.bind(this)(
316
359
  tableName,
317
- publishRulesExcludingFileTable,
360
+ publishRulesExcludingInferredTables,
318
361
  clientReq,
319
362
  clientInfo,
320
363
  scope,
@@ -331,7 +374,7 @@ export class PublishParser {
331
374
  return applyScopeToTableRules(
332
375
  tableName,
333
376
  tableHandler,
334
- parsePublishTableRule(publishRulesExcludingFileTable),
377
+ parsePublishTableRule(publishRulesExcludingInferredTables),
335
378
  scope,
336
379
  );
337
380
  }
@@ -1,4 +1,4 @@
1
- import { getObjectEntries, isDefined, isEmpty } from "prostgles-types";
1
+ import { fromEntries, getObjectEntries, isDefined, isEmpty } from "prostgles-types";
2
2
  import type { TableHandler } from "../DboBuilder/TableHandler/TableHandler";
3
3
  import { type ParsedTableRule, type PermissionScope } from "./PublishParser";
4
4
  export const applyScopeToTableRules = (
@@ -68,9 +68,3 @@ export const applyScopeToTableRules = (
68
68
  ) as ParsedTableRule;
69
69
  return result;
70
70
  };
71
-
72
- export const fromEntries = <K extends string | number | symbol, V>(
73
- entries: readonly (readonly [K, V])[],
74
- ): Record<K, V> => {
75
- return Object.fromEntries(entries) as Record<K, V>;
76
- };
@@ -5,6 +5,7 @@ import { parseFieldFilter } from "../DboBuilder/ViewHandler/parseFieldFilter";
5
5
  import type { PublishParser } from "./PublishParser";
6
6
  import type { ParsedPublishTable, PublishObject, UpdateRule } from "./publishTypesAndUtils";
7
7
  import type { LocalParams } from "../DboBuilder/DboBuilder";
8
+ import { isFileVersionTable } from "../StorageClient/fileVersionUtils";
8
9
 
9
10
  /**
10
11
  * Permissions for referencedTables columns are propagated to the file table (even if file table has no permissions)
@@ -28,7 +29,12 @@ export async function getFileTableRules(
28
29
  const forcedUpdateFilters: FullFilter<AnyObject, void>[] = [];
29
30
  const allowedNestedInserts: { table: string; column: string }[] = [];
30
31
  const referencedColumns = this.prostgles.dboBuilder.tablesOrViews
31
- ?.filter((t) => !t.is_view && t.name !== fileTableName)
32
+ ?.filter(
33
+ (t) =>
34
+ !t.is_view &&
35
+ t.name !== fileTableName &&
36
+ !isFileVersionTable(this.prostgles.opts.fileTable, t.name),
37
+ )
32
38
  .map((t) => {
33
39
  const refCols = t.columns.filter((c) =>
34
40
  c.references?.some((r) => r.ftable === fileTableName),
@@ -0,0 +1,57 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import type { FileTableConfig } from "../ProstglesTypes";
4
+ import { parseFieldFilter } from "../DboBuilder/ViewHandler/parseFieldFilter";
5
+ import type { PublishParser } from "./PublishParser";
6
+ import { getFileVersionTableRules } from "./getFileVersionTableRules";
7
+
8
+ void test("file version rules inherit fields and restrictive select options", async () => {
9
+ const fileColumns = ["id", "updated", "metadata"];
10
+ const versionColumns = ["id", "file_id", "created", "metadata"];
11
+ const getHandler = (columns: string[]) => ({
12
+ column_names: columns,
13
+ parseFieldFilter: (fields: any = "*") => parseFieldFilter(fields, true, columns),
14
+ });
15
+ const parser = {
16
+ dbo: {
17
+ files: getHandler(fileColumns),
18
+ files_versions: getHandler(versionColumns),
19
+ },
20
+ getTableRules: () => Promise.resolve({
21
+ select: {
22
+ fields: "*",
23
+ maxLimit: 5,
24
+ subscribeThrottle: 20,
25
+ disableMethods: { subscribe: 1 },
26
+ },
27
+ }),
28
+ } as unknown as PublishParser;
29
+
30
+ const rules = await getFileVersionTableRules.call(
31
+ parser,
32
+ { tableName: "files", versioning: {} } as FileTableConfig,
33
+ {
34
+ select: {
35
+ fields: "*",
36
+ maxLimit: 10,
37
+ subscribeThrottle: 10,
38
+ disableMethods: { sync: 1 },
39
+ },
40
+ },
41
+ undefined,
42
+ undefined,
43
+ undefined,
44
+ undefined,
45
+ );
46
+
47
+ assert(rules?.select);
48
+ assert.deepEqual(rules.select.fields, {
49
+ id: 1,
50
+ file_id: 1,
51
+ created: 1,
52
+ metadata: 1,
53
+ });
54
+ assert.equal(rules.select.maxLimit, 5);
55
+ assert.equal(rules.select.subscribeThrottle, 20);
56
+ assert.deepEqual(rules.select.disableMethods, { subscribe: 1, sync: 1 });
57
+ });
@@ -0,0 +1,106 @@
1
+ import { fromEntries } from "prostgles-types";
2
+ import type { AuthClientRequest, AuthResultWithSID } from "../Auth/AuthTypes";
3
+ import type { LocalParams } from "../DboBuilder/DboBuilder";
4
+ import type { FileTableConfig } from "../ProstglesTypes";
5
+ import type { PublishParser } from "./PublishParser";
6
+ import type { ParsedPublishTable, PublishObject } from "./publishTypesAndUtils";
7
+ import { getFileVersionTableName } from "../StorageClient/fileVersionUtils";
8
+ import type { FileTableRow, FileVersionTableRow } from "../StorageClient/fileTableDefinitions";
9
+
10
+ export const getFileVersionTableRules = async function (
11
+ this: PublishParser,
12
+ config: FileTableConfig,
13
+ explicitRules: ParsedPublishTable | undefined,
14
+ clientReq: AuthClientRequest | undefined,
15
+ clientInfo: AuthResultWithSID | undefined,
16
+ scope: LocalParams["scope"] | undefined,
17
+ resolvedPublishObject: PublishObject | undefined,
18
+ ): Promise<ParsedPublishTable | undefined> {
19
+ const versionTableName = getFileVersionTableName(config);
20
+ if (
21
+ resolvedPublishObject &&
22
+ Object.hasOwn(resolvedPublishObject, versionTableName) &&
23
+ !explicitRules?.select
24
+ ) {
25
+ return;
26
+ }
27
+
28
+ const fileRules = await this.getTableRules({
29
+ tableName: config.tableName,
30
+ clientReq,
31
+ clientInfo,
32
+ scope,
33
+ resolvedPublishObject,
34
+ });
35
+ if (!fileRules?.select) return;
36
+
37
+ const versionHandler = this.dbo[versionTableName];
38
+ if (!versionHandler) throw new Error(`File version table not found: ${versionTableName}`);
39
+ const fileHandler = this.dbo[config.tableName];
40
+ if (!fileHandler) throw new Error(`File table not found: ${config.tableName}`);
41
+ const select = explicitRules?.select;
42
+ const requestedFields = versionHandler.parseFieldFilter(select?.fields ?? "*");
43
+ const fileSelectFields = fileHandler.parseFieldFilter(fileRules.select.fields);
44
+ const fields = (versionHandler.column_names as (keyof FileVersionTableRow)[]).filter(
45
+ (field) =>
46
+ requestedFields.includes(field) &&
47
+ fileSelectFields.includes(getFileVersionSourceField(field)) &&
48
+ (fileHandler.column_names as (keyof FileTableRow)[]).includes(
49
+ getFileVersionSourceField(field),
50
+ ),
51
+ );
52
+ const requestedFilterFields = versionHandler.parseFieldFilter(select?.filterFields ?? fields);
53
+ const requestedOrderByFields = versionHandler.parseFieldFilter(select?.orderByFields ?? fields);
54
+ const inheritedFilter = {
55
+ $existsJoined: {
56
+ path: [{ table: config.tableName, on: [{ file_id: "id" }] }],
57
+ filter: fileRules.select.forcedFilter ?? {},
58
+ },
59
+ };
60
+
61
+ return {
62
+ select: {
63
+ ...fileRules.select,
64
+ ...select,
65
+ fields: fromEntries(fields.map((field) => [field, 1 as const] as const)),
66
+ filterFields: fromEntries(
67
+ fields
68
+ .filter((field) => requestedFilterFields.includes(field))
69
+ .map((field) => [field, 1 as const] as const),
70
+ ),
71
+ orderByFields: fromEntries(
72
+ fields
73
+ .filter((field) => requestedOrderByFields.includes(field))
74
+ .map((field) => [field, 1 as const] as const),
75
+ ),
76
+ forcedFilter:
77
+ select?.forcedFilter ? { $and: [inheritedFilter, select.forcedFilter] } : inheritedFilter,
78
+ maxLimit: getMostRestrictiveLimit(fileRules.select.maxLimit, select?.maxLimit),
79
+ subscribeThrottle: Math.max(
80
+ fileRules.select.subscribeThrottle ?? 0,
81
+ select?.subscribeThrottle ?? 0,
82
+ ),
83
+ disableMethods: {
84
+ ...fileRules.select.disableMethods,
85
+ ...select?.disableMethods,
86
+ },
87
+ },
88
+ };
89
+ };
90
+
91
+ const getFileVersionSourceField = (field: keyof FileVersionTableRow): keyof FileTableRow => {
92
+ if (field === "file_id") return "id";
93
+ if (field === "created") return "updated";
94
+ return field;
95
+ };
96
+
97
+ const getMostRestrictiveLimit = (
98
+ inheritedLimit: number | null | undefined,
99
+ explicitLimit: number | null | undefined,
100
+ ) => {
101
+ const limits = [inheritedLimit, explicitLimit].filter(
102
+ (limit): limit is number => typeof limit === "number",
103
+ );
104
+ if (limits.length) return Math.min(...limits);
105
+ return inheritedLimit === null || explicitLimit === null ? null : undefined;
106
+ };
@@ -1,5 +1,7 @@
1
+ import { isObject } from "prostgles-types";
1
2
  import type { PublishParser } from "./PublishParser";
2
3
  import { type PublishObject } from "./PublishParser";
4
+ import { getFileVersionTableName, isFileVersionTable } from "../StorageClient/fileVersionUtils";
3
5
 
4
6
  export const getPublishedTableNames = (
5
7
  publishParserInstance: PublishParser,
@@ -23,12 +25,41 @@ export const getPublishedTableNames = (
23
25
  publishParserInstance.dbo[fileTableName]?.is_media &&
24
26
  !tableNames.includes(fileTableName)
25
27
  ) {
26
- const isReferenced = publishParserInstance.prostgles.dboBuilder.tablesOrViews?.some((t) =>
27
- t.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName)),
28
+ const isReferenced = publishParserInstance.prostgles.dboBuilder.tablesOrViews?.some(
29
+ (t) =>
30
+ !isFileVersionTable(publishParserInstance.prostgles.opts.fileTable, t.name) &&
31
+ t.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName)),
28
32
  );
29
33
  if (isReferenced) {
30
34
  tableNames.unshift(fileTableName);
31
35
  }
32
36
  }
37
+
38
+ const fileConfig = publishParserInstance.prostgles.opts.fileTable;
39
+ if (fileConfig?.versioning && tableNames.includes(fileConfig.tableName)) {
40
+ const versionTableName = getFileVersionTableName(fileConfig);
41
+ if (!tableNames.includes(versionTableName)) {
42
+ tableNames.unshift(versionTableName);
43
+ }
44
+ }
45
+
46
+ const audit = publishParserInstance.prostgles.resolvedAuditConfig;
47
+ const publishedFileTableName =
48
+ fileTableName && tableNames.includes(fileTableName) ? fileTableName : undefined;
49
+ if (
50
+ audit &&
51
+ !tableNames.includes(audit.tableName) &&
52
+ Object.keys(audit.tables).some((tableName) => {
53
+ const rule = publishObject[tableName];
54
+ return (
55
+ tableName === publishedFileTableName ||
56
+ rule === "*" ||
57
+ rule === true ||
58
+ (isObject(rule) && Boolean(rule.select))
59
+ );
60
+ })
61
+ ) {
62
+ tableNames.unshift(audit.tableName);
63
+ }
33
64
  return tableNames;
34
65
  };
@@ -228,11 +228,6 @@ export type SelectRule<Cols extends AnyObject = AnyObject, S extends DBSchema |
228
228
  * */
229
229
  filterFields?: FieldFilter<Cols>;
230
230
 
231
- /**
232
- * Validation logic to check/update data for each request
233
- */
234
- validate?(args: SelectRequestData): SelectRequestData | Promise<SelectRequestData>;
235
-
236
231
  subscribeThrottle?: number;
237
232
 
238
233
  disableMethods?: Partial<Record<"sync" | "subscribe", 1>>;
@@ -1,5 +1,6 @@
1
1
  import type { DB } from "../Prostgles";
2
2
  import type { FileTableConfig } from "../ProstglesTypes";
3
+ import { getFileVersionTableName } from "./fileVersionUtils";
3
4
 
4
5
  export const deleteUnreferencedFile = async (
5
6
  db: DB,
@@ -11,8 +12,25 @@ export const deleteUnreferencedFile = async (
11
12
  const referenced = await db.tx(async (tx) => {
12
13
  await tx.none("SET LOCAL row_security = off");
13
14
  return tx.oneOrNone<{ found: number }>(
14
- "SELECT 1 FROM ${table:name} WHERE storage_key = ${key}::uuid OR (storage_key IS NULL AND id = ${key}::uuid) LIMIT 1",
15
- { table: config.tableName, key: storageKey },
15
+ `SELECT 1 AS found
16
+ WHERE EXISTS (
17
+ SELECT 1 FROM \${fileTable:name}
18
+ WHERE storage_key = \${key}::uuid OR (storage_key IS NULL AND id = \${key}::uuid)
19
+ )
20
+ ${
21
+ config.versioning ?
22
+ `OR EXISTS (
23
+ SELECT 1 FROM \${versionTable:name}
24
+ WHERE storage_key = \${key}::uuid
25
+ )`
26
+ : ""
27
+ }
28
+ LIMIT 1`,
29
+ {
30
+ fileTable: config.tableName,
31
+ versionTable: getFileVersionTableName(config),
32
+ key: storageKey,
33
+ },
16
34
  );
17
35
  });
18
36
  if (!referenced) await config.storageClient.delete(storageKey);
@@ -0,0 +1,52 @@
1
+ import { omitKeys } from "prostgles-types";
2
+ import type { TableRowFromColumnDefinitions } from "../TableConfig/TableRowFromColumnDefinitions";
3
+
4
+ export const FILE_TABLE_COLUMN_DEFINITIONS = {
5
+ id: `UUID PRIMARY KEY DEFAULT gen_random_uuid()`,
6
+ /**
7
+ * NULL for legacy objects stored under their file ID.
8
+ * */
9
+ storage_key: `UUID UNIQUE`,
10
+ extension: `TEXT NOT NULL DEFAULT ''`,
11
+ content_type: `TEXT NOT NULL DEFAULT ''`,
12
+ content_length: `BIGINT NOT NULL DEFAULT 0`,
13
+ etag: `TEXT NOT NULL DEFAULT ''`,
14
+ original_name: `TEXT NOT NULL`,
15
+ original_last_modified: `TIMESTAMPTZ`,
16
+ description: `TEXT`,
17
+ url: `TEXT NOT NULL DEFAULT ''`,
18
+ cloud_url: `TEXT`,
19
+ signed_url: `TEXT`,
20
+ signed_url_expires: `BIGINT`,
21
+ added: `TIMESTAMP NOT NULL DEFAULT NOW()`,
22
+ updated: `TIMESTAMP NOT NULL DEFAULT NOW()`,
23
+ deleted: `TIMESTAMPTZ`,
24
+ deleted_from_storage: `TIMESTAMPTZ`,
25
+ data: `BYTEA NOT NULL CHECK (data = decode('01', 'hex'))`, // Used as a placeholder to ensure insert types are correct. Actual data is uploaded to storageClient and not stored in the DB
26
+ } as const;
27
+
28
+ export const FILE_TABLE_VERSION_COLUMN_DEFINITIONS = {
29
+ version: `INTEGER NOT NULL DEFAULT 1`,
30
+ } as const;
31
+
32
+ export const FILE_VERSION_TABLE_COLUMN_DEFINITIONS = {
33
+ ...omitKeys(FILE_TABLE_COLUMN_DEFINITIONS, ["data"]),
34
+ storage_key: `UUID NOT NULL`,
35
+ file_id: `UUID NOT NULL`, // FK constraint is added later on
36
+ version: `INTEGER NOT NULL`,
37
+ created: `TIMESTAMP NOT NULL DEFAULT NOW()`,
38
+ } as const;
39
+
40
+ export type FileTableInsertRow = TableRowFromColumnDefinitions<
41
+ typeof FILE_TABLE_COLUMN_DEFINITIONS
42
+ > &
43
+ Partial<TableRowFromColumnDefinitions<typeof FILE_TABLE_VERSION_COLUMN_DEFINITIONS>>;
44
+ export type FileTableRow = Required<
45
+ TableRowFromColumnDefinitions<typeof FILE_TABLE_COLUMN_DEFINITIONS>
46
+ > &
47
+ Partial<Required<TableRowFromColumnDefinitions<typeof FILE_TABLE_VERSION_COLUMN_DEFINITIONS>>>;
48
+
49
+ export type FileVersionTableInsertRow = TableRowFromColumnDefinitions<
50
+ typeof FILE_VERSION_TABLE_COLUMN_DEFINITIONS
51
+ >;
52
+ export type FileVersionTableRow = Required<FileVersionTableInsertRow>;
@@ -0,0 +1,37 @@
1
+ import type { TableHandler } from "prostgles-types";
2
+ import type { TableHandlers } from "../DboBuilder/DboBuilder";
3
+ import type { FileTableConfig } from "../ProstglesTypes";
4
+ import type {
5
+ FileTableRow,
6
+ FileVersionTableInsertRow,
7
+ FileVersionTableRow,
8
+ } from "./fileTableDefinitions";
9
+
10
+ type FileVersionTableSchema = {
11
+ fileVersions: {
12
+ columns: FileVersionTableRow;
13
+ insertColumns: FileVersionTableInsertRow;
14
+ };
15
+ };
16
+
17
+ export const getFileVersionTableName = (config: FileTableConfig) =>
18
+ config.versioning?.tableName ?? `${config.tableName}_versions`;
19
+
20
+ export const isFileVersionTable = (
21
+ config: FileTableConfig | undefined,
22
+ tableName: string,
23
+ ): config is FileTableConfig & { versioning: NonNullable<FileTableConfig["versioning"]> } =>
24
+ Boolean(config?.versioning && getFileVersionTableName(config) === tableName);
25
+
26
+ export const getFileTableHandler = (dbo: TableHandlers, config: FileTableConfig) => {
27
+ const handler = dbo[config.tableName] as TableHandler<FileTableRow> | undefined;
28
+ if (!handler) throw new Error(`File table not found: ${config.tableName}`);
29
+ return handler;
30
+ };
31
+
32
+ export const getFileRevisionsTableHandler = (dbo: TableHandlers, config: FileTableConfig) => {
33
+ const handler = dbo[getFileVersionTableName(config)] as
34
+ TableHandler<FileVersionTableRow, FileVersionTableSchema, "fileVersions"> | undefined;
35
+ if (!handler) throw new Error(`File table not found: ${config.tableName}`);
36
+ return handler;
37
+ };
@@ -1,5 +1,14 @@
1
1
  import type { FileTableRow } from "./getFileTableConfig";
2
2
 
3
3
  /** Legacy files are stored under their logical ID. */
4
- export const getFileStorageKey = (file: Pick<FileTableRow, "id" | "storage_key">) =>
5
- file.storage_key ?? file.id;
4
+ export const getFileStorageKey = (
5
+ file: Pick<FileTableRow, "id" | "storage_key"> | { storage_key: string },
6
+ ) => {
7
+ const { storage_key } = file;
8
+ const id = "id" in file ? file.id : undefined;
9
+ const key = storage_key ?? id;
10
+ if (!key) {
11
+ throw new Error("Unable to determine file storage key");
12
+ }
13
+ return key;
14
+ };
@@ -5,7 +5,10 @@ import { getFileTableConfig } from "./getFileTableConfig";
5
5
 
6
6
  void test("managed files preserve hooks on other tables and append file hooks", () => {
7
7
  const guard = { afterEach: [{ commands: { insert: 1 }, validate: async () => {} }] };
8
- const fileGuard = { beforeEach: [{ commands: { insert: 1 }, validate: async () => {} }] };
8
+ const fileGuard = {
9
+ beforeEach: [{ commands: { insert: 1 }, validate: async () => {} }],
10
+ afterEach: [{ commands: { insert: 1 }, validate: async () => {} }],
11
+ };
9
12
  const prostgles = {
10
13
  opts: {
11
14
  fileTable: { tableName: "files", storageClient: {}, expressApp: {} },
@@ -16,4 +19,6 @@ void test("managed files preserve hooks on other tables and append file hooks",
16
19
  assert.equal(result.tableHooks?.documents, guard);
17
20
  assert.equal(result.tableHooks.files?.beforeEach?.length, 2);
18
21
  assert.equal(result.tableHooks.files.beforeEach[1], fileGuard.beforeEach[0]);
22
+ assert.equal(result.tableHooks.files.afterEach?.length, 2);
23
+ assert.equal(result.tableHooks.files.afterEach[0], fileGuard.afterEach[0]);
19
24
  });