@memberjunction/core-entities-server 6.2.0-edge.5 → 6.2.0-edge.7

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 (214) hide show
  1. package/README.md +155 -100
  2. package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts +2 -0
  3. package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts.map +1 -1
  4. package/dist/custom/MJAIAgentExampleEntityServer.server.js +8 -5
  5. package/dist/custom/MJAIAgentExampleEntityServer.server.js.map +1 -1
  6. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts +2 -0
  7. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts.map +1 -1
  8. package/dist/custom/MJAIAgentNoteEntityServer.server.js +8 -5
  9. package/dist/custom/MJAIAgentNoteEntityServer.server.js.map +1 -1
  10. package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts +17 -0
  11. package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts.map +1 -0
  12. package/dist/custom/MJAIAgentRelationshipEntityServer.server.js +71 -0
  13. package/dist/custom/MJAIAgentRelationshipEntityServer.server.js.map +1 -0
  14. package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts +8 -39
  15. package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts.map +1 -1
  16. package/dist/custom/MJAIAgentSessionEntityServer.server.js +44 -44
  17. package/dist/custom/MJAIAgentSessionEntityServer.server.js.map +1 -1
  18. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts +23 -0
  19. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts.map +1 -0
  20. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js +53 -0
  21. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js.map +1 -0
  22. package/dist/custom/MJAIPromptEntityServer.server.d.ts.map +1 -1
  23. package/dist/custom/MJAIPromptEntityServer.server.js +2 -1
  24. package/dist/custom/MJAIPromptEntityServer.server.js.map +1 -1
  25. package/dist/custom/MJBrandKitEntityServer.server.d.ts +14 -0
  26. package/dist/custom/MJBrandKitEntityServer.server.d.ts.map +1 -0
  27. package/dist/custom/MJBrandKitEntityServer.server.js +75 -0
  28. package/dist/custom/MJBrandKitEntityServer.server.js.map +1 -0
  29. package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts.map +1 -1
  30. package/dist/custom/MJCompanyIntegrationEntityServer.server.js +1 -0
  31. package/dist/custom/MJCompanyIntegrationEntityServer.server.js.map +1 -1
  32. package/dist/custom/MJComponentEntityServer.server.d.ts +11 -0
  33. package/dist/custom/MJComponentEntityServer.server.d.ts.map +1 -1
  34. package/dist/custom/MJComponentEntityServer.server.js +30 -2
  35. package/dist/custom/MJComponentEntityServer.server.js.map +1 -1
  36. package/dist/custom/MJConversationEntityServer.server.d.ts +13 -0
  37. package/dist/custom/MJConversationEntityServer.server.d.ts.map +1 -0
  38. package/dist/custom/MJConversationEntityServer.server.js +33 -0
  39. package/dist/custom/MJConversationEntityServer.server.js.map +1 -0
  40. package/dist/custom/MJDashboardEntityServer.server.d.ts +14 -0
  41. package/dist/custom/MJDashboardEntityServer.server.d.ts.map +1 -0
  42. package/dist/custom/MJDashboardEntityServer.server.js +38 -0
  43. package/dist/custom/MJDashboardEntityServer.server.js.map +1 -0
  44. package/dist/custom/MJDuplicateRunEntityServer.server.d.ts +34 -2
  45. package/dist/custom/MJDuplicateRunEntityServer.server.d.ts.map +1 -1
  46. package/dist/custom/MJDuplicateRunEntityServer.server.js +103 -23
  47. package/dist/custom/MJDuplicateRunEntityServer.server.js.map +1 -1
  48. package/dist/custom/MJEntityAlternateBaseViewEntityServer.server.d.ts +73 -0
  49. package/dist/custom/MJEntityAlternateBaseViewEntityServer.server.d.ts.map +1 -0
  50. package/dist/custom/MJEntityAlternateBaseViewEntityServer.server.js +391 -0
  51. package/dist/custom/MJEntityAlternateBaseViewEntityServer.server.js.map +1 -0
  52. package/dist/custom/MJEntityDocumentEntityServer.server.d.ts.map +1 -1
  53. package/dist/custom/MJEntityDocumentEntityServer.server.js +1 -0
  54. package/dist/custom/MJEntityDocumentEntityServer.server.js.map +1 -1
  55. package/dist/custom/MJEntityFieldPermissionEntityServer.server.d.ts +96 -22
  56. package/dist/custom/MJEntityFieldPermissionEntityServer.server.d.ts.map +1 -1
  57. package/dist/custom/MJEntityFieldPermissionEntityServer.server.js +239 -55
  58. package/dist/custom/MJEntityFieldPermissionEntityServer.server.js.map +1 -1
  59. package/dist/custom/MJListDetailEntityServer.server.d.ts.map +1 -1
  60. package/dist/custom/MJListDetailEntityServer.server.js +1 -0
  61. package/dist/custom/MJListDetailEntityServer.server.js.map +1 -1
  62. package/dist/custom/MJQueryEntityServer.server.d.ts +184 -46
  63. package/dist/custom/MJQueryEntityServer.server.d.ts.map +1 -1
  64. package/dist/custom/MJQueryEntityServer.server.js +505 -159
  65. package/dist/custom/MJQueryEntityServer.server.js.map +1 -1
  66. package/dist/custom/MJQuerySQLEntityServer.server.d.ts +15 -18
  67. package/dist/custom/MJQuerySQLEntityServer.server.d.ts.map +1 -1
  68. package/dist/custom/MJQuerySQLEntityServer.server.js +34 -42
  69. package/dist/custom/MJQuerySQLEntityServer.server.js.map +1 -1
  70. package/dist/custom/MJTagEntityServer.server.d.ts +2 -0
  71. package/dist/custom/MJTagEntityServer.server.d.ts.map +1 -1
  72. package/dist/custom/MJTagEntityServer.server.js +13 -7
  73. package/dist/custom/MJTagEntityServer.server.js.map +1 -1
  74. package/dist/custom/MJUserRoleEntityServer.server.d.ts +74 -7
  75. package/dist/custom/MJUserRoleEntityServer.server.d.ts.map +1 -1
  76. package/dist/custom/MJUserRoleEntityServer.server.js +206 -20
  77. package/dist/custom/MJUserRoleEntityServer.server.js.map +1 -1
  78. package/dist/custom/MJUserRoutineEntityServer.server.d.ts.map +1 -1
  79. package/dist/custom/MJUserRoutineEntityServer.server.js +8 -1
  80. package/dist/custom/MJUserRoutineEntityServer.server.js.map +1 -1
  81. package/dist/custom/MJUserViewEntityServer.server.d.ts +17 -1
  82. package/dist/custom/MJUserViewEntityServer.server.d.ts.map +1 -1
  83. package/dist/custom/MJUserViewEntityServer.server.js +95 -7
  84. package/dist/custom/MJUserViewEntityServer.server.js.map +1 -1
  85. package/dist/custom/MJVectorIndexEntityServer.server.d.ts +2 -0
  86. package/dist/custom/MJVectorIndexEntityServer.server.d.ts.map +1 -1
  87. package/dist/custom/MJVectorIndexEntityServer.server.js +33 -0
  88. package/dist/custom/MJVectorIndexEntityServer.server.js.map +1 -1
  89. package/dist/custom/anonymousOwnershipKeyGuard.d.ts +42 -0
  90. package/dist/custom/anonymousOwnershipKeyGuard.d.ts.map +1 -0
  91. package/dist/custom/anonymousOwnershipKeyGuard.js +36 -0
  92. package/dist/custom/anonymousOwnershipKeyGuard.js.map +1 -0
  93. package/dist/custom/approvalStamp.d.ts +37 -0
  94. package/dist/custom/approvalStamp.d.ts.map +1 -0
  95. package/dist/custom/approvalStamp.js +67 -0
  96. package/dist/custom/approvalStamp.js.map +1 -0
  97. package/dist/custom/fieldPermissionAccess.d.ts +31 -0
  98. package/dist/custom/fieldPermissionAccess.d.ts.map +1 -0
  99. package/dist/custom/fieldPermissionAccess.js +38 -0
  100. package/dist/custom/fieldPermissionAccess.js.map +1 -0
  101. package/dist/custom/fieldPermissionReconciler.d.ts.map +1 -1
  102. package/dist/custom/fieldPermissionReconciler.js +12 -2
  103. package/dist/custom/fieldPermissionReconciler.js.map +1 -1
  104. package/dist/custom/query-extraction/childRowWriter.d.ts +77 -0
  105. package/dist/custom/query-extraction/childRowWriter.d.ts.map +1 -0
  106. package/dist/custom/query-extraction/childRowWriter.js +277 -0
  107. package/dist/custom/query-extraction/childRowWriter.js.map +1 -0
  108. package/dist/custom/query-extraction/compositionTargets.d.ts +40 -0
  109. package/dist/custom/query-extraction/compositionTargets.d.ts.map +1 -0
  110. package/dist/custom/query-extraction/compositionTargets.js +99 -0
  111. package/dist/custom/query-extraction/compositionTargets.js.map +1 -0
  112. package/dist/custom/query-extraction/declared.d.ts +79 -0
  113. package/dist/custom/query-extraction/declared.d.ts.map +1 -0
  114. package/dist/custom/query-extraction/declared.js +91 -0
  115. package/dist/custom/query-extraction/declared.js.map +1 -0
  116. package/dist/custom/query-extraction/describeFacts.d.ts +40 -0
  117. package/dist/custom/query-extraction/describeFacts.d.ts.map +1 -0
  118. package/dist/custom/query-extraction/describeFacts.js +225 -0
  119. package/dist/custom/query-extraction/describeFacts.js.map +1 -0
  120. package/dist/custom/query-extraction/descriptionPass.d.ts +23 -0
  121. package/dist/custom/query-extraction/descriptionPass.d.ts.map +1 -0
  122. package/dist/custom/query-extraction/descriptionPass.js +95 -0
  123. package/dist/custom/query-extraction/descriptionPass.js.map +1 -0
  124. package/dist/custom/query-extraction/extractQuery.d.ts +25 -0
  125. package/dist/custom/query-extraction/extractQuery.d.ts.map +1 -0
  126. package/dist/custom/query-extraction/extractQuery.js +146 -0
  127. package/dist/custom/query-extraction/extractQuery.js.map +1 -0
  128. package/dist/custom/query-extraction/extractionTypes.d.ts +133 -0
  129. package/dist/custom/query-extraction/extractionTypes.d.ts.map +1 -0
  130. package/dist/custom/query-extraction/extractionTypes.js +2 -0
  131. package/dist/custom/query-extraction/extractionTypes.js.map +1 -0
  132. package/dist/custom/query-extraction/index.d.ts +16 -0
  133. package/dist/custom/query-extraction/index.d.ts.map +1 -1
  134. package/dist/custom/query-extraction/index.js +11 -1
  135. package/dist/custom/query-extraction/index.js.map +1 -1
  136. package/dist/custom/query-extraction/pipeline.d.ts +6 -2
  137. package/dist/custom/query-extraction/pipeline.d.ts.map +1 -1
  138. package/dist/custom/query-extraction/pipeline.js +21 -14
  139. package/dist/custom/query-extraction/pipeline.js.map +1 -1
  140. package/dist/custom/query-extraction/resolve.d.ts +7 -2
  141. package/dist/custom/query-extraction/resolve.d.ts.map +1 -1
  142. package/dist/custom/query-extraction/resolve.js +41 -20
  143. package/dist/custom/query-extraction/resolve.js.map +1 -1
  144. package/dist/custom/query-extraction/sourceBinding.d.ts +57 -0
  145. package/dist/custom/query-extraction/sourceBinding.d.ts.map +1 -0
  146. package/dist/custom/query-extraction/sourceBinding.js +104 -0
  147. package/dist/custom/query-extraction/sourceBinding.js.map +1 -0
  148. package/dist/custom/query-extraction/sync.d.ts +28 -4
  149. package/dist/custom/query-extraction/sync.d.ts.map +1 -1
  150. package/dist/custom/query-extraction/sync.js +147 -59
  151. package/dist/custom/query-extraction/sync.js.map +1 -1
  152. package/dist/custom/query-extraction/templateFacts.d.ts +62 -0
  153. package/dist/custom/query-extraction/templateFacts.d.ts.map +1 -0
  154. package/dist/custom/query-extraction/templateFacts.js +229 -0
  155. package/dist/custom/query-extraction/templateFacts.js.map +1 -0
  156. package/dist/custom/query-extraction/types.d.ts +8 -0
  157. package/dist/custom/query-extraction/types.d.ts.map +1 -1
  158. package/dist/custom/query-refresh/QueryExtractionService.d.ts +54 -0
  159. package/dist/custom/query-refresh/QueryExtractionService.d.ts.map +1 -0
  160. package/dist/custom/query-refresh/QueryExtractionService.js +207 -0
  161. package/dist/custom/query-refresh/QueryExtractionService.js.map +1 -0
  162. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts +28 -0
  163. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts.map +1 -0
  164. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js +106 -0
  165. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js.map +1 -0
  166. package/dist/custom/query-refresh/index.d.ts +14 -0
  167. package/dist/custom/query-refresh/index.d.ts.map +1 -0
  168. package/dist/custom/query-refresh/index.js +10 -0
  169. package/dist/custom/query-refresh/index.js.map +1 -0
  170. package/dist/custom/query-refresh/queryRebind.d.ts +33 -0
  171. package/dist/custom/query-refresh/queryRebind.d.ts.map +1 -0
  172. package/dist/custom/query-refresh/queryRebind.js +85 -0
  173. package/dist/custom/query-refresh/queryRebind.js.map +1 -0
  174. package/dist/custom/query-refresh/refreshAuthorization.d.ts +29 -0
  175. package/dist/custom/query-refresh/refreshAuthorization.d.ts.map +1 -0
  176. package/dist/custom/query-refresh/refreshAuthorization.js +66 -0
  177. package/dist/custom/query-refresh/refreshAuthorization.js.map +1 -0
  178. package/dist/custom/query-refresh/refreshFormat.d.ts +16 -0
  179. package/dist/custom/query-refresh/refreshFormat.d.ts.map +1 -0
  180. package/dist/custom/query-refresh/refreshFormat.js +67 -0
  181. package/dist/custom/query-refresh/refreshFormat.js.map +1 -0
  182. package/dist/custom/query-refresh/refreshOrder.d.ts +25 -0
  183. package/dist/custom/query-refresh/refreshOrder.d.ts.map +1 -0
  184. package/dist/custom/query-refresh/refreshOrder.js +95 -0
  185. package/dist/custom/query-refresh/refreshOrder.js.map +1 -0
  186. package/dist/custom/query-refresh/refreshSelection.d.ts +15 -0
  187. package/dist/custom/query-refresh/refreshSelection.d.ts.map +1 -0
  188. package/dist/custom/query-refresh/refreshSelection.js +99 -0
  189. package/dist/custom/query-refresh/refreshSelection.js.map +1 -0
  190. package/dist/custom/query-refresh/refreshTypes.d.ts +81 -0
  191. package/dist/custom/query-refresh/refreshTypes.d.ts.map +1 -0
  192. package/dist/custom/query-refresh/refreshTypes.js +5 -0
  193. package/dist/custom/query-refresh/refreshTypes.js.map +1 -0
  194. package/dist/custom/systemUserGuardState.d.ts +73 -0
  195. package/dist/custom/systemUserGuardState.d.ts.map +1 -0
  196. package/dist/custom/systemUserGuardState.js +161 -0
  197. package/dist/custom/systemUserGuardState.js.map +1 -0
  198. package/dist/custom/template-extraction/parser.js +5 -2
  199. package/dist/custom/template-extraction/parser.js.map +1 -1
  200. package/dist/custom/template-extraction/types.d.ts +1 -1
  201. package/dist/custom/template-extraction/types.d.ts.map +1 -1
  202. package/dist/custom/util.d.ts +8 -0
  203. package/dist/custom/util.d.ts.map +1 -1
  204. package/dist/custom/util.js +18 -1
  205. package/dist/custom/util.js.map +1 -1
  206. package/dist/engines/QueryEngineServer.d.ts +4 -1
  207. package/dist/engines/QueryEngineServer.d.ts.map +1 -1
  208. package/dist/engines/QueryEngineServer.js +10 -7
  209. package/dist/engines/QueryEngineServer.js.map +1 -1
  210. package/dist/index.d.ts +9 -0
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +9 -0
  213. package/dist/index.js.map +1 -1
  214. package/package.json +30 -30
@@ -0,0 +1,207 @@
1
+ import { DatabaseProviderBase, LogError, RunInEntityTransaction } from "@memberjunction/core";
2
+ import { EscapeSQLString, NormalizeUUID } from "@memberjunction/global";
3
+ import { EntityIDsOfExtraction, QueryRefreshUnavailableMessage, UserCanRefreshQueries, UserCanSeeQuerySources, } from "./refreshAuthorization.js";
4
+ import { OrderForRefresh } from "./refreshOrder.js";
5
+ import { SelectQueriesForRefresh } from "./refreshSelection.js";
6
+ /**
7
+ * Re-establishes saved queries' facts from their SQL and the database server, on demand: the
8
+ * same extraction a save of a changed query runs, without changing the SQL. Every entry point
9
+ * (the `Query.RefreshExtraction` remote operation, `mj query refresh`, CodeGen's re-bind pass)
10
+ * goes through this service, so the same authorization applies to all of them:
11
+ *
12
+ * - the caller needs Update on `MJ: Queries` and Create, Update and Delete on its derived child
13
+ * entities, for a dry run too;
14
+ * - the caller must be able to read every entity the query reads, with no field denied on any of
15
+ * them, because the report and the written rows expose their columns;
16
+ * - a refusal of a single query reads exactly like "not found"; a bulk run reports such a query
17
+ * as `NotPermitted`, with no reason.
18
+ *
19
+ * Each query is refreshed in its own transaction on the caller's provider, and the child rows are
20
+ * written as the caller, so each write's own permission check also applies. A bulk run refreshes
21
+ * the queries a composition depends on before the queries that compose them.
22
+ */
23
+ export class QueryExtractionService {
24
+ constructor(context) {
25
+ this.context = context;
26
+ }
27
+ /**
28
+ * Refreshes one saved query.
29
+ *
30
+ * @param queryID - The query's ID; echoed, and nothing else, when the query is unavailable.
31
+ */
32
+ async RefreshQuery(queryID, options = {}) {
33
+ if (!this.userCanRefresh)
34
+ return unavailableReport(queryID, options);
35
+ const query = await this.loadQuery(queryID);
36
+ if (!query)
37
+ return unavailableReport(queryID, options);
38
+ return this.refreshLoaded(query, options, 'Unavailable', queryID);
39
+ }
40
+ /**
41
+ * Refreshes every query `filter` selects that the caller can read, dependencies first. An ID
42
+ * or name that selects nothing is reported as `Unavailable`; a selected query the caller may
43
+ * not refresh is reported as `NotPermitted`.
44
+ */
45
+ async RefreshQueries(filter, options = {}) {
46
+ const dryRun = options.DryRun === true;
47
+ const selection = await this.select(filter);
48
+ if (!selection)
49
+ return unselectableRun(filter, options);
50
+ const order = OrderForRefresh(selection.Queries, selection.Edges);
51
+ const reports = selection.Unmatched.map(label => unavailableReport(label, options));
52
+ const total = order.Order.length;
53
+ for (const [index, query] of order.Order.entries()) {
54
+ const report = await this.refreshSelected(query, options);
55
+ reports.push(report);
56
+ options.OnProgress?.({ Processed: index + 1, Total: total, Report: report });
57
+ }
58
+ return { DryRun: dryRun, Reports: reports, Cycles: order.Cycles };
59
+ }
60
+ /**
61
+ * The queries `filter` selects; `null` when a caller who may not refresh queries cannot read
62
+ * them either, so the selection cannot be made (a caller who may refresh and still cannot read
63
+ * them meets the read's error).
64
+ */
65
+ async select(filter) {
66
+ try {
67
+ return await SelectQueriesForRefresh(this.context, filter);
68
+ }
69
+ catch (e) {
70
+ if (this.userCanRefresh)
71
+ throw e;
72
+ return null;
73
+ }
74
+ }
75
+ get userCanRefresh() {
76
+ return UserCanRefreshQueries(this.context.User, this.context.Provider.Entities);
77
+ }
78
+ async refreshSelected(selected, options) {
79
+ if (!this.userCanRefresh)
80
+ return notPermittedReport(selected.ID, selected.Name, options);
81
+ const query = await this.loadQuery(selected.ID);
82
+ if (!query)
83
+ return notPermittedReport(selected.ID, selected.Name, options);
84
+ return this.refreshLoaded(query, options, 'NotPermitted', selected.ID);
85
+ }
86
+ /** The query as the caller can load it; `null` when it does not exist or the caller cannot read it. */
87
+ async loadQuery(queryID) {
88
+ try {
89
+ const query = await this.context.Provider.GetEntityObject('MJ: Queries', this.context.User);
90
+ return await query.Load(queryID) ? query : null;
91
+ }
92
+ catch (e) {
93
+ LogError(`[QueryExtractionService] query ${queryID} could not be loaded: ${e instanceof Error ? e.message : String(e)}`);
94
+ return null;
95
+ }
96
+ }
97
+ async refreshLoaded(query, options, refusal, label) {
98
+ const dryRun = options.DryRun === true;
99
+ try {
100
+ if (!query.SQL || query.SQL.trim().length === 0) {
101
+ return { ...emptyReport(query.ID, query.Name, 'Unchanged', dryRun), Diagnostics: ['The query has no SQL, so there is nothing to refresh.'] };
102
+ }
103
+ const extraction = await query.ComputeRefreshExtractionAsync();
104
+ if (!await this.userCanSeeSources(query.ID, extraction)) {
105
+ return refusal === 'Unavailable' ? unavailableReport(label, options) : notPermittedReport(query.ID, query.Name, options);
106
+ }
107
+ const rowChanges = queryRowChanges(query, extraction);
108
+ const preview = await query.PreviewRefreshAsync(extraction, id => this.entityName(id));
109
+ const summary = dryRun || !needsWrite(preview, rowChanges, options)
110
+ ? preview
111
+ : await this.applyInTransaction(query, extraction, options.WithAI === true);
112
+ return reportOf(query, extraction, summary, rowChanges, dryRun);
113
+ }
114
+ catch (e) {
115
+ const reason = e instanceof Error ? e.message : String(e);
116
+ LogError(`[QueryExtractionService] refresh of query "${query.Name}" failed: ${reason}`);
117
+ return { ...emptyReport(query.ID, query.Name, 'Failed', dryRun), Diagnostics: [`The refresh was not completed and nothing was written: ${reason}`] };
118
+ }
119
+ }
120
+ /** Writes the refresh in its own transaction on the caller's provider; any failure rolls it back. */
121
+ async applyInTransaction(query, extraction, withAI) {
122
+ const provider = this.context.Provider;
123
+ const work = () => query.ApplyRefreshAsync(extraction, withAI);
124
+ return provider instanceof DatabaseProviderBase ? RunInEntityTransaction(provider, work) : work();
125
+ }
126
+ /**
127
+ * The non-disclosure guard: whether the caller can see every entity the query reads, by its
128
+ * stored links and field sources and by the facts the refresh found.
129
+ */
130
+ async userCanSeeSources(queryID, extraction) {
131
+ const filter = `QueryID='${EscapeSQLString(queryID)}'`;
132
+ const [links, fields] = await this.context.Provider.RunViews([
133
+ { EntityName: 'MJ: Query Entities', ExtraFilter: filter, Fields: ['EntityID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true },
134
+ { EntityName: 'MJ: Query Fields', ExtraFilter: filter, Fields: ['SourceEntityID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true },
135
+ ], this.context.User);
136
+ if (!links?.Success || !fields?.Success)
137
+ return false;
138
+ const stored = [...links.Results.map(r => r.EntityID), ...fields.Results.map(r => r.SourceEntityID)]
139
+ .filter((id) => typeof id === 'string' && id.length > 0);
140
+ return UserCanSeeQuerySources(this.context.User, [...stored, ...EntityIDsOfExtraction(extraction)], this.context.Provider.Entities);
141
+ }
142
+ entityName(entityID) {
143
+ const wanted = NormalizeUUID(entityID);
144
+ return this.context.Provider.Entities.find(e => NormalizeUUID(e.ID) === wanted)?.Name ?? entityID;
145
+ }
146
+ }
147
+ /**
148
+ * Whether a refresh has anything to write: a child row or a query-row column changes, or the
149
+ * description pass was asked for and some row has no description. An unchanged query is not saved
150
+ * at all, so its timestamps and embedding stay as they are.
151
+ */
152
+ function needsWrite(preview, rowChanges, options) {
153
+ if (preview.Changes.length > 0 || rowChanges.length > 0)
154
+ return true;
155
+ return options.WithAI === true && preview.FieldsWithoutDescription.length + preview.ParametersWithoutDescription.length > 0;
156
+ }
157
+ /**
158
+ * The run for a caller who may neither refresh nor read queries:
159
+ * each ID or name it gave is reported unavailable, and nothing else is selected or disclosed.
160
+ */
161
+ function unselectableRun(filter, options) {
162
+ const labels = [...(filter.QueryIDs ?? []), ...(filter.QueryNames ?? [])];
163
+ return { DryRun: options.DryRun === true, Reports: labels.map(label => unavailableReport(label, options)), Cycles: [] };
164
+ }
165
+ /** The columns of the query row the refresh changes (`UsesTemplate` and the Extraction columns). */
166
+ function queryRowChanges(query, extraction) {
167
+ const message = extraction.Messages.length > 0 ? extraction.Messages.join('\n') : null;
168
+ const changes = [];
169
+ if (query.UsesTemplate !== extraction.UsesTemplate)
170
+ changes.push('UsesTemplate');
171
+ if (query.ExtractedSQLHash !== extraction.Hash)
172
+ changes.push('ExtractedSQLHash');
173
+ if (query.ExtractionStatus !== extraction.Status)
174
+ changes.push('ExtractionStatus');
175
+ if ((query.ExtractionMessage ?? null) !== message)
176
+ changes.push('ExtractionMessage');
177
+ return changes;
178
+ }
179
+ function reportOf(query, extraction, summary, rowChanges, dryRun) {
180
+ const changes = summary?.Changes ?? [];
181
+ const pick = (action) => changes.filter(c => c.Action === action);
182
+ return {
183
+ QueryID: query.ID,
184
+ QueryName: query.Name,
185
+ Outcome: changes.length > 0 || rowChanges.length > 0 ? 'Refreshed' : 'Unchanged',
186
+ DryRun: dryRun,
187
+ ExtractionStatus: extraction.Status,
188
+ QueryColumns: [...rowChanges],
189
+ Added: pick('Added'),
190
+ Updated: pick('Updated'),
191
+ Removed: pick('Removed'),
192
+ Flagged: summary?.FlaggedParameters ?? [],
193
+ Diagnostics: [...extraction.Messages],
194
+ };
195
+ }
196
+ function emptyReport(queryID, queryName, outcome, dryRun) {
197
+ return { QueryID: queryID, QueryName: queryName, Outcome: outcome, DryRun: dryRun, ExtractionStatus: null, QueryColumns: [], Added: [], Updated: [], Removed: [], Flagged: [], Diagnostics: [] };
198
+ }
199
+ /** A query that does not exist or that the caller may not refresh: the two read alike, echoing only `label`. */
200
+ function unavailableReport(label, options) {
201
+ return { ...emptyReport(label, '', 'Unavailable', options.DryRun === true), Diagnostics: [QueryRefreshUnavailableMessage(label)] };
202
+ }
203
+ /** A selected query a bulk run skips because the caller may not refresh it; no reason is given. */
204
+ function notPermittedReport(queryID, queryName, options) {
205
+ return { ...emptyReport(queryID, queryName, 'NotPermitted', options.DryRun === true), Diagnostics: ['Skipped: not permitted.'] };
206
+ }
207
+ //# sourceMappingURL=QueryExtractionService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryExtractionService.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/QueryExtractionService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { IMetadataProvider, RemoteOpServerContext, UserInfo } from "@memberjunction/core";
2
+ import { QueryRefreshExtractionOperation } from "@memberjunction/core-entities";
3
+ import type { QueryRefreshExtractionInput, QueryRefreshExtractionOutput } from "@memberjunction/core-entities";
4
+ import type { QueryRefreshFilter, QueryRefreshRunReport } from "./refreshTypes.js";
5
+ /**
6
+ * Server implementation of the `Query.RefreshExtraction` remote operation: refreshes one saved
7
+ * query, or a selection, through {@link QueryExtractionService}, reporting each query as a
8
+ * progress event as it finishes.
9
+ *
10
+ * `Authorize` refuses a caller without Update on `MJ: Queries` and Create, Update and Delete on
11
+ * its child entities; the service applies the same check and the per-query non-disclosure guard
12
+ * for every entry point. An API-key caller also needs the operation's `query:refresh` scope.
13
+ * A request for exactly one query ID, and nothing else, reports a query that does not exist and
14
+ * one the caller may not refresh with the same message.
15
+ */
16
+ export declare class QueryRefreshExtractionServerOperation extends QueryRefreshExtractionOperation {
17
+ protected Authorize(_input: QueryRefreshExtractionInput, user: UserInfo): Promise<boolean>;
18
+ protected InternalExecute(input: QueryRefreshExtractionInput, provider: IMetadataProvider, user: UserInfo, context: RemoteOpServerContext): Promise<QueryRefreshExtractionOutput>;
19
+ }
20
+ /** The service filter for an operation input; only the selectors the input gives. */
21
+ export declare function RefreshFilterOf(input: QueryRefreshExtractionInput): QueryRefreshFilter;
22
+ /** Whether a filter selects anything at all. */
23
+ export declare function HasRefreshSelector(filter: QueryRefreshFilter): boolean;
24
+ /** A service run as the operation's output. */
25
+ export declare function RefreshOutputOf(run: QueryRefreshRunReport): QueryRefreshExtractionOutput;
26
+ /** Keeps the operation in the bundle: import and call it where the class must be registered. */
27
+ export declare function LoadQueryRefreshExtractionServerOperation(): void;
28
+ //# sourceMappingURL=QueryRefreshExtractionServerOperation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryRefreshExtractionServerOperation.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/QueryRefreshExtractionServerOperation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EACR,2BAA2B,EAC3B,4BAA4B,EAG/B,MAAM,+BAA+B,CAAC;AAOvC,OAAO,KAAK,EAAE,kBAAkB,EAA2C,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEzH;;;;;;;;;;GAUG;AACH,qBACa,qCAAsC,SAAQ,+BAA+B;cAC7D,SAAS,CAAC,MAAM,EAAE,2BAA2B,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;cAIzF,eAAe,CAAC,KAAK,EAAE,2BAA2B,EAAE,QAAQ,EAAE,iBAAiB,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,4BAA4B,CAAC;CAoB1L;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,KAAK,EAAE,2BAA2B,GAAG,kBAAkB,CAQtF;AAED,gDAAgD;AAChD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAGtE;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAAC,GAAG,EAAE,qBAAqB,GAAG,4BAA4B,CAOxF;AAqBD,gGAAgG;AAChG,wBAAgB,yCAAyC,IAAI,IAAI,CAEhE"}
@@ -0,0 +1,106 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { BaseRemotableOperation, Metadata } from "@memberjunction/core";
8
+ import { QueryRefreshExtractionOperation } from "@memberjunction/core-entities";
9
+ import { RegisterClass } from "@memberjunction/global";
10
+ import { QueryExtractionService } from "./QueryExtractionService.js";
11
+ import { UserCanRefreshQueries } from "./refreshAuthorization.js";
12
+ import { FormatQueryRefreshSummary } from "./refreshFormat.js";
13
+ import { IsQueryRefreshProvider } from "./refreshTypes.js";
14
+ /**
15
+ * Server implementation of the `Query.RefreshExtraction` remote operation: refreshes one saved
16
+ * query, or a selection, through {@link QueryExtractionService}, reporting each query as a
17
+ * progress event as it finishes.
18
+ *
19
+ * `Authorize` refuses a caller without Update on `MJ: Queries` and Create, Update and Delete on
20
+ * its child entities; the service applies the same check and the per-query non-disclosure guard
21
+ * for every entry point. An API-key caller also needs the operation's `query:refresh` scope.
22
+ * A request for exactly one query ID, and nothing else, reports a query that does not exist and
23
+ * one the caller may not refresh with the same message.
24
+ */
25
+ let QueryRefreshExtractionServerOperation = class QueryRefreshExtractionServerOperation extends QueryRefreshExtractionOperation {
26
+ async Authorize(_input, user) {
27
+ return UserCanRefreshQueries(user, Metadata.Provider.Entities); // global-provider-ok: Authorize receives no provider; entity permissions are process-global metadata
28
+ }
29
+ async InternalExecute(input, provider, user, context) {
30
+ if (!IsQueryRefreshProvider(provider))
31
+ throw new Error('Query.RefreshExtraction needs a database provider');
32
+ const filter = RefreshFilterOf(input);
33
+ if (!HasRefreshSelector(filter))
34
+ throw new Error('Give at least one selector: queryIDs, queryNames, categoryPath, entityNames or all.');
35
+ const service = new QueryExtractionService({ Provider: provider, User: user });
36
+ const options = {
37
+ DryRun: input.dryRun === true,
38
+ WithAI: input.withAI === true,
39
+ OnProgress: p => context.emitProgress({
40
+ OperationKey: this.OperationKey, Processed: p.Processed, Total: p.Total, Status: 'Running',
41
+ Message: `${p.Report.Outcome}: ${p.Report.QueryName || p.Report.QueryID}`,
42
+ Payload: { queryID: p.Report.QueryID, outcome: p.Report.Outcome },
43
+ }),
44
+ };
45
+ const single = filter.QueryIDs?.length === 1 && Object.keys(filter).length === 1 ? filter.QueryIDs[0] : null;
46
+ const run = single
47
+ ? { DryRun: options.DryRun === true, Reports: [await service.RefreshQuery(single, options)], Cycles: [] }
48
+ : await service.RefreshQueries(filter, options);
49
+ return RefreshOutputOf(run);
50
+ }
51
+ };
52
+ QueryRefreshExtractionServerOperation = __decorate([
53
+ RegisterClass(BaseRemotableOperation, 'Query.RefreshExtraction')
54
+ ], QueryRefreshExtractionServerOperation);
55
+ export { QueryRefreshExtractionServerOperation };
56
+ /** The service filter for an operation input; only the selectors the input gives. */
57
+ export function RefreshFilterOf(input) {
58
+ const filter = {};
59
+ if (input.queryIDs?.length)
60
+ filter.QueryIDs = input.queryIDs;
61
+ if (input.queryNames?.length)
62
+ filter.QueryNames = input.queryNames;
63
+ if (input.categoryPath?.trim())
64
+ filter.CategoryPath = input.categoryPath;
65
+ if (input.entityNames?.length)
66
+ filter.EntityNames = input.entityNames;
67
+ if (input.all === true)
68
+ filter.All = true;
69
+ return filter;
70
+ }
71
+ /** Whether a filter selects anything at all. */
72
+ export function HasRefreshSelector(filter) {
73
+ return filter.All === true || !!filter.QueryIDs?.length || !!filter.QueryNames?.length || !!filter.CategoryPath
74
+ || !!filter.EntityNames?.length || !!filter.EntityIDs?.length;
75
+ }
76
+ /** A service run as the operation's output. */
77
+ export function RefreshOutputOf(run) {
78
+ return {
79
+ dryRun: run.DryRun,
80
+ reports: run.Reports.map(reportOutputOf),
81
+ cycles: run.Cycles.map(c => [...c]),
82
+ summary: FormatQueryRefreshSummary(run),
83
+ };
84
+ }
85
+ function reportOutputOf(report) {
86
+ return {
87
+ queryID: report.QueryID,
88
+ queryName: report.QueryName,
89
+ outcome: report.Outcome,
90
+ ...(report.ExtractionStatus ? { extractionStatus: report.ExtractionStatus } : {}),
91
+ queryColumns: [...report.QueryColumns],
92
+ added: report.Added.map(changeOutputOf),
93
+ updated: report.Updated.map(changeOutputOf),
94
+ removed: report.Removed.map(changeOutputOf),
95
+ flagged: [...report.Flagged],
96
+ diagnostics: [...report.Diagnostics],
97
+ };
98
+ }
99
+ function changeOutputOf(change) {
100
+ return { collection: change.Collection, name: change.Name, changedColumns: [...change.ChangedColumns] };
101
+ }
102
+ /** Keeps the operation in the bundle: import and call it where the class must be registered. */
103
+ export function LoadQueryRefreshExtractionServerOperation() {
104
+ // The import is what registers the class.
105
+ }
106
+ //# sourceMappingURL=QueryRefreshExtractionServerOperation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryRefreshExtractionServerOperation.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/QueryRefreshExtractionServerOperation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export { QueryExtractionService } from "./QueryExtractionService.js";
2
+ export { UserCanRefreshQueries, UserCanSeeQuerySources, EntityIDsOfExtraction, QueryRefreshUnavailableMessage, QUERY_REFRESH_CHILD_ENTITIES, } from "./refreshAuthorization.js";
3
+ export { OrderForRefresh } from "./refreshOrder.js";
4
+ export type { OrderableQuery, CompositionEdge, RefreshOrder } from "./refreshOrder.js";
5
+ export { SelectQueriesForRefresh } from "./refreshSelection.js";
6
+ export type { RefreshSelection } from "./refreshSelection.js";
7
+ export type { QueryRefreshProvider, QueryRefreshFilter, QueryRefreshOptions, QueryRefreshProgress, QueryRefreshOutcome, QueryRefreshReport, QueryRefreshRunReport, QueryRefreshContext, } from "./refreshTypes.js";
8
+ export { RebindQueriesForChangedEntities, DefinerRightsDriftMessage } from "./queryRebind.js";
9
+ export type { QueryRebindResult, QueryDefinerRightsDrift } from "./queryRebind.js";
10
+ export { FormatQueryRefreshRun, FormatQueryRefreshReport, FormatQueryRefreshSummary, QueryRefreshTotalsOf } from "./refreshFormat.js";
11
+ export type { QueryRefreshTotals } from "./refreshFormat.js";
12
+ export { IsQueryRefreshProvider } from "./refreshTypes.js";
13
+ export { QueryRefreshExtractionServerOperation, LoadQueryRefreshExtractionServerOperation, RefreshFilterOf, HasRefreshSelector, RefreshOutputOf, } from "./QueryRefreshExtractionServerOperation.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,8BAA8B,EAC9B,4BAA4B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EACR,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,+BAA+B,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC3F,YAAY,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACnI,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACH,qCAAqC,EACrC,yCAAyC,EACzC,eAAe,EACf,kBAAkB,EAClB,eAAe,GAClB,MAAM,yCAAyC,CAAC"}
@@ -0,0 +1,10 @@
1
+ // Query refresh — re-establishing saved queries' facts on demand, and its authorization
2
+ export { QueryExtractionService } from "./QueryExtractionService.js";
3
+ export { UserCanRefreshQueries, UserCanSeeQuerySources, EntityIDsOfExtraction, QueryRefreshUnavailableMessage, QUERY_REFRESH_CHILD_ENTITIES, } from "./refreshAuthorization.js";
4
+ export { OrderForRefresh } from "./refreshOrder.js";
5
+ export { SelectQueriesForRefresh } from "./refreshSelection.js";
6
+ export { RebindQueriesForChangedEntities, DefinerRightsDriftMessage } from "./queryRebind.js";
7
+ export { FormatQueryRefreshRun, FormatQueryRefreshReport, FormatQueryRefreshSummary, QueryRefreshTotalsOf } from "./refreshFormat.js";
8
+ export { IsQueryRefreshProvider } from "./refreshTypes.js";
9
+ export { QueryRefreshExtractionServerOperation, LoadQueryRefreshExtractionServerOperation, RefreshFilterOf, HasRefreshSelector, RefreshOutputOf, } from "./QueryRefreshExtractionServerOperation.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,8BAA8B,EAC9B,4BAA4B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAY7D,OAAO,EAAE,+BAA+B,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAE3F,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEnI,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACH,qCAAqC,EACrC,yCAAyC,EACzC,eAAe,EACf,kBAAkB,EAClB,eAAe,GAClB,MAAM,yCAAyC,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { QueryRefreshContext, QueryRefreshRunReport } from "./refreshTypes.js";
2
+ /** A query that runs with definer's rights and gained a column field-level security restricts. */
3
+ export interface QueryDefinerRightsDrift {
4
+ readonly QueryID: string;
5
+ readonly QueryName: string;
6
+ /** The added output columns, each sourced from a field that has field permissions. */
7
+ readonly Fields: readonly string[];
8
+ }
9
+ /** What a re-bind pass did. */
10
+ export interface QueryRebindResult {
11
+ /** The changed entities the pass was given. */
12
+ readonly EntityCount: number;
13
+ readonly Run: QueryRefreshRunReport;
14
+ readonly Drift: readonly QueryDefinerRightsDrift[];
15
+ }
16
+ /**
17
+ * Re-binds the saved queries that read entities whose fields changed (a column added, dropped, or
18
+ * changed in type or nullability): each query that reads one of them (its `MJ: Query Entities`
19
+ * rows) is refreshed, with no description pass, so its fields follow the schema again. The SQL is
20
+ * never edited: a query the change broke is recorded with status `Error` and the database
21
+ * server's message.
22
+ *
23
+ * A query with `MJ: Query Permissions` rows runs with definer's rights: its role list alone
24
+ * authorizes a run, whatever the SQL reads. When such a query gains an output column (a `*` over
25
+ * a view that gained one) sourced from a field that has field permissions, the column now reaches
26
+ * every role on the list. The pass records that on the query as a `Warning` and returns it.
27
+ *
28
+ * @param entityIDs - The entities whose fields changed.
29
+ */
30
+ export declare function RebindQueriesForChangedEntities(context: QueryRefreshContext, entityIDs: readonly string[]): Promise<QueryRebindResult>;
31
+ /** The `ExtractionMessage` line for a definer's-rights query that gained restricted columns. */
32
+ export declare function DefinerRightsDriftMessage(fields: readonly string[]): string;
33
+ //# sourceMappingURL=queryRebind.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryRebind.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/queryRebind.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAsB,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAErG,kGAAkG;AAClG,MAAM,WAAW,uBAAuB;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,qBAAqB,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACtD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,+BAA+B,CAAC,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAO5I;AAkDD,gGAAgG;AAChG,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAI3E"}
@@ -0,0 +1,85 @@
1
+ import { LogError } from "@memberjunction/core";
2
+ import { EscapeSQLString, NormalizeUUID } from "@memberjunction/global";
3
+ import { QueryExtractionService } from "./QueryExtractionService.js";
4
+ /**
5
+ * Re-binds the saved queries that read entities whose fields changed (a column added, dropped, or
6
+ * changed in type or nullability): each query that reads one of them (its `MJ: Query Entities`
7
+ * rows) is refreshed, with no description pass, so its fields follow the schema again. The SQL is
8
+ * never edited: a query the change broke is recorded with status `Error` and the database
9
+ * server's message.
10
+ *
11
+ * A query with `MJ: Query Permissions` rows runs with definer's rights: its role list alone
12
+ * authorizes a run, whatever the SQL reads. When such a query gains an output column (a `*` over
13
+ * a view that gained one) sourced from a field that has field permissions, the column now reaches
14
+ * every role on the list. The pass records that on the query as a `Warning` and returns it.
15
+ *
16
+ * @param entityIDs - The entities whose fields changed.
17
+ */
18
+ export async function RebindQueriesForChangedEntities(context, entityIDs) {
19
+ const unique = [...new Set(entityIDs.map(NormalizeUUID))];
20
+ if (unique.length === 0)
21
+ return { EntityCount: 0, Run: { DryRun: false, Reports: [], Cycles: [] }, Drift: [] };
22
+ const run = await new QueryExtractionService(context).RefreshQueries({ EntityIDs: unique }, { WithAI: false });
23
+ const drift = await findDefinerRightsDrift(context, run.Reports);
24
+ for (const item of drift)
25
+ await recordDrift(context, item);
26
+ return { EntityCount: unique.length, Run: run, Drift: drift };
27
+ }
28
+ /** The refreshed queries that run with definer's rights and gained a column sourced from a field with field permissions. */
29
+ async function findDefinerRightsDrift(context, reports) {
30
+ const restricted = restrictedFieldIDs(context.Provider.Entities);
31
+ const candidates = reports
32
+ .map(r => ({ Report: r, Fields: r.Added.filter(c => c.Collection === 'Fields' && c.SourceEntityFieldID && restricted.has(NormalizeUUID(c.SourceEntityFieldID))) }))
33
+ .filter(c => c.Fields.length > 0);
34
+ if (candidates.length === 0)
35
+ return [];
36
+ const definerRights = await queriesWithPermissions(context, candidates.map(c => c.Report.QueryID));
37
+ return candidates
38
+ .filter(c => definerRights.has(NormalizeUUID(c.Report.QueryID)))
39
+ .map(c => ({ QueryID: c.Report.QueryID, QueryName: c.Report.QueryName, Fields: c.Fields.map(f => f.Name) }));
40
+ }
41
+ /** The IDs of fields that have field permissions, or that belong to an entity field-level security applies to. */
42
+ function restrictedFieldIDs(entities) {
43
+ const ids = new Set();
44
+ for (const entity of entities) {
45
+ for (const field of entity.Fields) {
46
+ if (field.HasFieldPermissions || entity.FieldLevelSecurityApplies)
47
+ ids.add(NormalizeUUID(field.ID));
48
+ }
49
+ }
50
+ return ids;
51
+ }
52
+ async function queriesWithPermissions(context, queryIDs) {
53
+ const list = queryIDs.map(id => `'${EscapeSQLString(id)}'`).join(',');
54
+ const result = await context.Provider.RunView({
55
+ EntityName: 'MJ: Query Permissions', ExtraFilter: `QueryID IN (${list})`, Fields: ['QueryID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true,
56
+ }, context.User);
57
+ if (!result.Success)
58
+ throw new Error(`the query permissions could not be read: ${result.ErrorMessage}`);
59
+ return new Set(result.Results.map(r => NormalizeUUID(r.QueryID)));
60
+ }
61
+ /** Records the drift on the query: status `Warning` (unless it is already `Error`) and a message line. */
62
+ async function recordDrift(context, drift) {
63
+ const message = DefinerRightsDriftMessage(drift.Fields);
64
+ try {
65
+ const query = await context.Provider.GetEntityObject('MJ: Queries', context.User);
66
+ if (!await query.Load(drift.QueryID))
67
+ throw new Error('the query could not be loaded');
68
+ if (query.ExtractionStatus !== 'Error')
69
+ query.ExtractionStatus = 'Warning';
70
+ query.ExtractionMessage = query.ExtractionMessage ? `${query.ExtractionMessage}\n${message}` : message;
71
+ query.ExtractionOverride = 'Skip';
72
+ if (!await query.Save())
73
+ throw new Error(query.LatestResult?.CompleteMessage ?? 'the save failed');
74
+ }
75
+ catch (e) {
76
+ LogError(`[RebindQueriesForChangedEntities] the definer's-rights warning for query "${drift.QueryName}" could not be recorded: ${e instanceof Error ? e.message : String(e)}`);
77
+ }
78
+ }
79
+ /** The `ExtractionMessage` line for a definer's-rights query that gained restricted columns. */
80
+ export function DefinerRightsDriftMessage(fields) {
81
+ return `The query's output gained ${fields.map(f => `"${f}"`).join(', ')}, sourced from fields restricted by field-level security. ` +
82
+ 'The query is authorized by its Query Permissions role list alone, so every role on that list can now read these columns. ' +
83
+ 'Review the role list, or name the columns the query returns instead of using *.';
84
+ }
85
+ //# sourceMappingURL=queryRebind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryRebind.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/queryRebind.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAExE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAmBlE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,OAA4B,EAAE,SAA4B;IAC5G,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAC1D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC/G,MAAM,GAAG,GAAG,MAAM,IAAI,sBAAsB,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/G,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACjE,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAClE,CAAC;AAED,4HAA4H;AAC5H,KAAK,UAAU,sBAAsB,CAAC,OAA4B,EAAE,OAAsC;IACtG,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,CAAC,mBAAmB,IAAI,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAClK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACtC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACnG,OAAO,UAAU;SACZ,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;SAC/D,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AACrH,CAAC;AAED,kHAAkH;AAClH,SAAS,kBAAkB,CAAC,QAA+B;IACvD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,mBAAmB,IAAI,MAAM,CAAC,yBAAyB;gBAAE,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QACxG,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,OAA4B,EAAE,QAA2B;IAC3F,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;QAC/D,UAAU,EAAE,uBAAuB,EAAE,WAAW,EAAE,eAAe,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI;KAC9J,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IACxG,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,0GAA0G;AAC1G,KAAK,UAAU,WAAW,CAAC,OAA4B,EAAE,KAA8B;IACnF,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsB,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACvG,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACvF,IAAI,KAAK,CAAC,gBAAgB,KAAK,OAAO;YAAE,KAAK,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAC3E,KAAK,CAAC,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,iBAAiB,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACvG,KAAK,CAAC,kBAAkB,GAAG,MAAM,CAAC;QAClC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,eAAe,IAAI,iBAAiB,CAAC,CAAC;IACvG,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,QAAQ,CAAC,6EAA6E,KAAK,CAAC,SAAS,4BAA4B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnL,CAAC;AACL,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,yBAAyB,CAAC,MAAyB;IAC/D,OAAO,6BAA6B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,4DAA4D;QAChI,2HAA2H;QAC3H,iFAAiF,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { EntityInfo, UserInfo } from "@memberjunction/core";
2
+ import type { QueryExtractionResult } from "../query-extraction/index.js";
3
+ /** The child entities a refresh creates, updates and deletes rows of. */
4
+ export declare const QUERY_REFRESH_CHILD_ENTITIES: readonly string[];
5
+ /**
6
+ * Whether `user` may refresh queries at all: Update on `MJ: Queries`, and Create, Update and
7
+ * Delete on each of its derived child entities. A dry run needs the same, since its report
8
+ * discloses the same metadata. Run permissions (`MJ: Query Permissions`) play no part: refreshing
9
+ * is an authoring act.
10
+ */
11
+ export declare function UserCanRefreshQueries(user: UserInfo, entities: readonly EntityInfo[]): boolean;
12
+ /**
13
+ * Whether `user` may see what a refresh of one query reveals: the column names, types and
14
+ * sources of every entity the query reads. True only when the user can read every one of those
15
+ * entities and is denied no field on any of them.
16
+ *
17
+ * @param entityIDs - The entities the query reads: its stored links and field sources, and the ones
18
+ * the refresh found ({@link EntityIDsOfExtraction}).
19
+ */
20
+ export declare function UserCanSeeQuerySources(user: UserInfo, entityIDs: Iterable<string>, entities: readonly EntityInfo[]): boolean;
21
+ /** The entities a refresh's facts link the query to: the entities it reads and its fields' sources. */
22
+ export declare function EntityIDsOfExtraction(extraction: QueryExtractionResult): string[];
23
+ /**
24
+ * The message for a refresh of a query that does not exist or that the caller may not refresh.
25
+ * The two are worded identically, so a refusal does not confirm that the query, or anything it
26
+ * reads, exists. It echoes only the identifier the caller supplied.
27
+ */
28
+ export declare function QueryRefreshUnavailableMessage(label: string): string;
29
+ //# sourceMappingURL=refreshAuthorization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshAuthorization.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshAuthorization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE,yEAAyE;AACzE,eAAO,MAAM,4BAA4B,EAAE,SAAS,MAAM,EAKzD,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAU9F;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAS5H;AAED,uGAAuG;AACvG,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAMjF;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE"}