@memberjunction/core-entities-server 6.2.0-edge.6 → 6.2.0-edge.8

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 (179) hide show
  1. package/README.md +155 -100
  2. package/dist/custom/AnchoredConversationReadSecurityHook.d.ts +22 -0
  3. package/dist/custom/AnchoredConversationReadSecurityHook.d.ts.map +1 -0
  4. package/dist/custom/AnchoredConversationReadSecurityHook.js +293 -0
  5. package/dist/custom/AnchoredConversationReadSecurityHook.js.map +1 -0
  6. package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts +2 -0
  7. package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts.map +1 -1
  8. package/dist/custom/MJAIAgentExampleEntityServer.server.js +8 -5
  9. package/dist/custom/MJAIAgentExampleEntityServer.server.js.map +1 -1
  10. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts +2 -0
  11. package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts.map +1 -1
  12. package/dist/custom/MJAIAgentNoteEntityServer.server.js +8 -5
  13. package/dist/custom/MJAIAgentNoteEntityServer.server.js.map +1 -1
  14. package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts +17 -0
  15. package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts.map +1 -0
  16. package/dist/custom/MJAIAgentRelationshipEntityServer.server.js +71 -0
  17. package/dist/custom/MJAIAgentRelationshipEntityServer.server.js.map +1 -0
  18. package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts +8 -22
  19. package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts.map +1 -1
  20. package/dist/custom/MJAIAgentSessionEntityServer.server.js +24 -1
  21. package/dist/custom/MJAIAgentSessionEntityServer.server.js.map +1 -1
  22. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts +23 -0
  23. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts.map +1 -0
  24. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js +53 -0
  25. package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js.map +1 -0
  26. package/dist/custom/MJAIPromptEntityServer.server.d.ts.map +1 -1
  27. package/dist/custom/MJAIPromptEntityServer.server.js +2 -1
  28. package/dist/custom/MJAIPromptEntityServer.server.js.map +1 -1
  29. package/dist/custom/MJBrandKitEntityServer.server.d.ts +14 -0
  30. package/dist/custom/MJBrandKitEntityServer.server.d.ts.map +1 -0
  31. package/dist/custom/MJBrandKitEntityServer.server.js +75 -0
  32. package/dist/custom/MJBrandKitEntityServer.server.js.map +1 -0
  33. package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts.map +1 -1
  34. package/dist/custom/MJCompanyIntegrationEntityServer.server.js +1 -0
  35. package/dist/custom/MJCompanyIntegrationEntityServer.server.js.map +1 -1
  36. package/dist/custom/MJComponentEntityServer.server.d.ts +2 -0
  37. package/dist/custom/MJComponentEntityServer.server.d.ts.map +1 -1
  38. package/dist/custom/MJComponentEntityServer.server.js +5 -1
  39. package/dist/custom/MJComponentEntityServer.server.js.map +1 -1
  40. package/dist/custom/MJConversationDetailEntityServer.server.d.ts +20 -30
  41. package/dist/custom/MJConversationDetailEntityServer.server.d.ts.map +1 -1
  42. package/dist/custom/MJConversationDetailEntityServer.server.js +89 -35
  43. package/dist/custom/MJConversationDetailEntityServer.server.js.map +1 -1
  44. package/dist/custom/MJConversationEntityServer.server.d.ts +19 -4
  45. package/dist/custom/MJConversationEntityServer.server.d.ts.map +1 -1
  46. package/dist/custom/MJConversationEntityServer.server.js +169 -11
  47. package/dist/custom/MJConversationEntityServer.server.js.map +1 -1
  48. package/dist/custom/MJEntityDocumentEntityServer.server.d.ts.map +1 -1
  49. package/dist/custom/MJEntityDocumentEntityServer.server.js +1 -0
  50. package/dist/custom/MJEntityDocumentEntityServer.server.js.map +1 -1
  51. package/dist/custom/MJListDetailEntityServer.server.d.ts.map +1 -1
  52. package/dist/custom/MJListDetailEntityServer.server.js +1 -0
  53. package/dist/custom/MJListDetailEntityServer.server.js.map +1 -1
  54. package/dist/custom/MJProjectEntityServer.server.d.ts +21 -0
  55. package/dist/custom/MJProjectEntityServer.server.d.ts.map +1 -0
  56. package/dist/custom/MJProjectEntityServer.server.js +106 -0
  57. package/dist/custom/MJProjectEntityServer.server.js.map +1 -0
  58. package/dist/custom/MJQueryEntityServer.server.d.ts +177 -47
  59. package/dist/custom/MJQueryEntityServer.server.d.ts.map +1 -1
  60. package/dist/custom/MJQueryEntityServer.server.js +479 -164
  61. package/dist/custom/MJQueryEntityServer.server.js.map +1 -1
  62. package/dist/custom/MJQuerySQLEntityServer.server.d.ts +15 -18
  63. package/dist/custom/MJQuerySQLEntityServer.server.d.ts.map +1 -1
  64. package/dist/custom/MJQuerySQLEntityServer.server.js +34 -42
  65. package/dist/custom/MJQuerySQLEntityServer.server.js.map +1 -1
  66. package/dist/custom/MJTagEntityServer.server.d.ts +2 -0
  67. package/dist/custom/MJTagEntityServer.server.d.ts.map +1 -1
  68. package/dist/custom/MJTagEntityServer.server.js +13 -7
  69. package/dist/custom/MJTagEntityServer.server.js.map +1 -1
  70. package/dist/custom/MJUserRoutineEntityServer.server.d.ts.map +1 -1
  71. package/dist/custom/MJUserRoutineEntityServer.server.js +8 -1
  72. package/dist/custom/MJUserRoutineEntityServer.server.js.map +1 -1
  73. package/dist/custom/RestrictedFieldCommentClassifier.d.ts +73 -0
  74. package/dist/custom/RestrictedFieldCommentClassifier.d.ts.map +1 -0
  75. package/dist/custom/RestrictedFieldCommentClassifier.js +240 -0
  76. package/dist/custom/RestrictedFieldCommentClassifier.js.map +1 -0
  77. package/dist/custom/query-extraction/childRowWriter.d.ts +77 -0
  78. package/dist/custom/query-extraction/childRowWriter.d.ts.map +1 -0
  79. package/dist/custom/query-extraction/childRowWriter.js +277 -0
  80. package/dist/custom/query-extraction/childRowWriter.js.map +1 -0
  81. package/dist/custom/query-extraction/compositionTargets.d.ts +40 -0
  82. package/dist/custom/query-extraction/compositionTargets.d.ts.map +1 -0
  83. package/dist/custom/query-extraction/compositionTargets.js +99 -0
  84. package/dist/custom/query-extraction/compositionTargets.js.map +1 -0
  85. package/dist/custom/query-extraction/declared.d.ts +79 -0
  86. package/dist/custom/query-extraction/declared.d.ts.map +1 -0
  87. package/dist/custom/query-extraction/declared.js +91 -0
  88. package/dist/custom/query-extraction/declared.js.map +1 -0
  89. package/dist/custom/query-extraction/describeFacts.d.ts +40 -0
  90. package/dist/custom/query-extraction/describeFacts.d.ts.map +1 -0
  91. package/dist/custom/query-extraction/describeFacts.js +225 -0
  92. package/dist/custom/query-extraction/describeFacts.js.map +1 -0
  93. package/dist/custom/query-extraction/descriptionPass.d.ts +23 -0
  94. package/dist/custom/query-extraction/descriptionPass.d.ts.map +1 -0
  95. package/dist/custom/query-extraction/descriptionPass.js +95 -0
  96. package/dist/custom/query-extraction/descriptionPass.js.map +1 -0
  97. package/dist/custom/query-extraction/extractQuery.d.ts +25 -0
  98. package/dist/custom/query-extraction/extractQuery.d.ts.map +1 -0
  99. package/dist/custom/query-extraction/extractQuery.js +146 -0
  100. package/dist/custom/query-extraction/extractQuery.js.map +1 -0
  101. package/dist/custom/query-extraction/extractionTypes.d.ts +133 -0
  102. package/dist/custom/query-extraction/extractionTypes.d.ts.map +1 -0
  103. package/dist/custom/query-extraction/extractionTypes.js +2 -0
  104. package/dist/custom/query-extraction/extractionTypes.js.map +1 -0
  105. package/dist/custom/query-extraction/index.d.ts +16 -0
  106. package/dist/custom/query-extraction/index.d.ts.map +1 -1
  107. package/dist/custom/query-extraction/index.js +11 -1
  108. package/dist/custom/query-extraction/index.js.map +1 -1
  109. package/dist/custom/query-extraction/pipeline.d.ts +6 -2
  110. package/dist/custom/query-extraction/pipeline.d.ts.map +1 -1
  111. package/dist/custom/query-extraction/pipeline.js +21 -14
  112. package/dist/custom/query-extraction/pipeline.js.map +1 -1
  113. package/dist/custom/query-extraction/resolve.d.ts +7 -2
  114. package/dist/custom/query-extraction/resolve.d.ts.map +1 -1
  115. package/dist/custom/query-extraction/resolve.js +17 -14
  116. package/dist/custom/query-extraction/resolve.js.map +1 -1
  117. package/dist/custom/query-extraction/sourceBinding.d.ts +57 -0
  118. package/dist/custom/query-extraction/sourceBinding.d.ts.map +1 -0
  119. package/dist/custom/query-extraction/sourceBinding.js +104 -0
  120. package/dist/custom/query-extraction/sourceBinding.js.map +1 -0
  121. package/dist/custom/query-extraction/sync.d.ts +27 -3
  122. package/dist/custom/query-extraction/sync.d.ts.map +1 -1
  123. package/dist/custom/query-extraction/sync.js +69 -44
  124. package/dist/custom/query-extraction/sync.js.map +1 -1
  125. package/dist/custom/query-extraction/templateFacts.d.ts +62 -0
  126. package/dist/custom/query-extraction/templateFacts.d.ts.map +1 -0
  127. package/dist/custom/query-extraction/templateFacts.js +229 -0
  128. package/dist/custom/query-extraction/templateFacts.js.map +1 -0
  129. package/dist/custom/query-extraction/types.d.ts +4 -0
  130. package/dist/custom/query-extraction/types.d.ts.map +1 -1
  131. package/dist/custom/query-refresh/QueryExtractionService.d.ts +54 -0
  132. package/dist/custom/query-refresh/QueryExtractionService.d.ts.map +1 -0
  133. package/dist/custom/query-refresh/QueryExtractionService.js +207 -0
  134. package/dist/custom/query-refresh/QueryExtractionService.js.map +1 -0
  135. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts +28 -0
  136. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts.map +1 -0
  137. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js +106 -0
  138. package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js.map +1 -0
  139. package/dist/custom/query-refresh/index.d.ts +14 -0
  140. package/dist/custom/query-refresh/index.d.ts.map +1 -0
  141. package/dist/custom/query-refresh/index.js +10 -0
  142. package/dist/custom/query-refresh/index.js.map +1 -0
  143. package/dist/custom/query-refresh/queryRebind.d.ts +33 -0
  144. package/dist/custom/query-refresh/queryRebind.d.ts.map +1 -0
  145. package/dist/custom/query-refresh/queryRebind.js +85 -0
  146. package/dist/custom/query-refresh/queryRebind.js.map +1 -0
  147. package/dist/custom/query-refresh/refreshAuthorization.d.ts +29 -0
  148. package/dist/custom/query-refresh/refreshAuthorization.d.ts.map +1 -0
  149. package/dist/custom/query-refresh/refreshAuthorization.js +66 -0
  150. package/dist/custom/query-refresh/refreshAuthorization.js.map +1 -0
  151. package/dist/custom/query-refresh/refreshFormat.d.ts +16 -0
  152. package/dist/custom/query-refresh/refreshFormat.d.ts.map +1 -0
  153. package/dist/custom/query-refresh/refreshFormat.js +67 -0
  154. package/dist/custom/query-refresh/refreshFormat.js.map +1 -0
  155. package/dist/custom/query-refresh/refreshOrder.d.ts +25 -0
  156. package/dist/custom/query-refresh/refreshOrder.d.ts.map +1 -0
  157. package/dist/custom/query-refresh/refreshOrder.js +95 -0
  158. package/dist/custom/query-refresh/refreshOrder.js.map +1 -0
  159. package/dist/custom/query-refresh/refreshSelection.d.ts +15 -0
  160. package/dist/custom/query-refresh/refreshSelection.d.ts.map +1 -0
  161. package/dist/custom/query-refresh/refreshSelection.js +99 -0
  162. package/dist/custom/query-refresh/refreshSelection.js.map +1 -0
  163. package/dist/custom/query-refresh/refreshTypes.d.ts +81 -0
  164. package/dist/custom/query-refresh/refreshTypes.d.ts.map +1 -0
  165. package/dist/custom/query-refresh/refreshTypes.js +5 -0
  166. package/dist/custom/query-refresh/refreshTypes.js.map +1 -0
  167. package/dist/custom/util.d.ts +8 -0
  168. package/dist/custom/util.d.ts.map +1 -1
  169. package/dist/custom/util.js +18 -1
  170. package/dist/custom/util.js.map +1 -1
  171. package/dist/engines/QueryEngineServer.d.ts +8 -5
  172. package/dist/engines/QueryEngineServer.d.ts.map +1 -1
  173. package/dist/engines/QueryEngineServer.js +16 -23
  174. package/dist/engines/QueryEngineServer.js.map +1 -1
  175. package/dist/index.d.ts +7 -0
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +7 -0
  178. package/dist/index.js.map +1 -1
  179. package/package.json +30 -30
@@ -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"}
@@ -0,0 +1,66 @@
1
+ import { NormalizeUUID } from "@memberjunction/global";
2
+ /** The child entities a refresh creates, updates and deletes rows of. */
3
+ export const QUERY_REFRESH_CHILD_ENTITIES = [
4
+ 'MJ: Query Fields',
5
+ 'MJ: Query Parameters',
6
+ 'MJ: Query Entities',
7
+ 'MJ: Query Dependencies',
8
+ ];
9
+ /**
10
+ * Whether `user` may refresh queries at all: Update on `MJ: Queries`, and Create, Update and
11
+ * Delete on each of its derived child entities. A dry run needs the same, since its report
12
+ * discloses the same metadata. Run permissions (`MJ: Query Permissions`) play no part: refreshing
13
+ * is an authoring act.
14
+ */
15
+ export function UserCanRefreshQueries(user, entities) {
16
+ const byName = new Map(entities.map(e => [e.Name.toLowerCase(), e]));
17
+ const query = byName.get('mj: queries');
18
+ if (!query || !query.GetUserPermisions(user)?.CanUpdate)
19
+ return false;
20
+ return QUERY_REFRESH_CHILD_ENTITIES.every(name => {
21
+ const entity = byName.get(name.toLowerCase());
22
+ if (!entity)
23
+ return false;
24
+ const permissions = entity.GetUserPermisions(user);
25
+ return !!permissions && permissions.CanCreate && permissions.CanUpdate && permissions.CanDelete;
26
+ });
27
+ }
28
+ /**
29
+ * Whether `user` may see what a refresh of one query reveals: the column names, types and
30
+ * sources of every entity the query reads. True only when the user can read every one of those
31
+ * entities and is denied no field on any of them.
32
+ *
33
+ * @param entityIDs - The entities the query reads: its stored links and field sources, and the ones
34
+ * the refresh found ({@link EntityIDsOfExtraction}).
35
+ */
36
+ export function UserCanSeeQuerySources(user, entityIDs, entities) {
37
+ const byID = new Map(entities.map(e => [NormalizeUUID(e.ID), e]));
38
+ for (const id of entityIDs) {
39
+ const entity = byID.get(NormalizeUUID(id));
40
+ if (!entity)
41
+ return false;
42
+ if (!entity.GetUserPermisions(user)?.CanRead)
43
+ return false;
44
+ if (entity.FieldLevelSecurityApplies && entity.GetDeniedReadFields(user).size > 0)
45
+ return false;
46
+ }
47
+ return true;
48
+ }
49
+ /** The entities a refresh's facts link the query to: the entities it reads and its fields' sources. */
50
+ export function EntityIDsOfExtraction(extraction) {
51
+ const ids = (extraction.Entities ?? []).map(e => e.EntityID);
52
+ for (const field of extraction.Fields ?? []) {
53
+ if (field.SourceEntityID)
54
+ ids.push(field.SourceEntityID);
55
+ }
56
+ return ids;
57
+ }
58
+ /**
59
+ * The message for a refresh of a query that does not exist or that the caller may not refresh.
60
+ * The two are worded identically, so a refusal does not confirm that the query, or anything it
61
+ * reads, exists. It echoes only the identifier the caller supplied.
62
+ */
63
+ export function QueryRefreshUnavailableMessage(label) {
64
+ return `Query '${label}' does not exist or you do not have permission to refresh it.`;
65
+ }
66
+ //# sourceMappingURL=refreshAuthorization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshAuthorization.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshAuthorization.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,yEAAyE;AACzE,MAAM,CAAC,MAAM,4BAA4B,GAAsB;IAC3D,kBAAkB;IAClB,sBAAsB;IACtB,oBAAoB;IACpB,wBAAwB;CAC3B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAc,EAAE,QAA+B;IACjF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,SAAS;QAAE,OAAO,KAAK,CAAC;IACtE,OAAO,4BAA4B,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,CAAC,CAAC,WAAW,IAAI,WAAW,CAAC,SAAS,IAAI,WAAW,CAAC,SAAS,IAAI,WAAW,CAAC,SAAS,CAAC;IACpG,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAc,EAAE,SAA2B,EAAE,QAA+B;IAC/G,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3D,IAAI,MAAM,CAAC,yBAAyB,IAAI,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IACpG,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,qBAAqB,CAAC,UAAiC;IACnE,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7D,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,cAAc;YAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,8BAA8B,CAAC,KAAa;IACxD,OAAO,UAAU,KAAK,+DAA+D,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { QueryRefreshOutcome, QueryRefreshReport, QueryRefreshRunReport } from "./refreshTypes.js";
2
+ /** How many queries of a run ended in each outcome. */
3
+ export type QueryRefreshTotals = Record<QueryRefreshOutcome, number>;
4
+ /** The number of reports per outcome. */
5
+ export declare function QueryRefreshTotalsOf(run: QueryRefreshRunReport): QueryRefreshTotals;
6
+ /** One line summing a run up: `12 refreshed, 19 unchanged, 0 failed (dry run)`. */
7
+ export declare function FormatQueryRefreshSummary(run: QueryRefreshRunReport): string;
8
+ /**
9
+ * The lines of a run's report: one heading per query, then its row changes, flagged parameters
10
+ * and diagnostics, then any composition cycles and the summary. With `changedOnly`, unchanged
11
+ * queries with no diagnostics are left out.
12
+ */
13
+ export declare function FormatQueryRefreshRun(run: QueryRefreshRunReport, changedOnly?: boolean): string[];
14
+ /** The lines of one query's report. */
15
+ export declare function FormatQueryRefreshReport(report: QueryRefreshReport): string[];
16
+ //# sourceMappingURL=refreshFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshFormat.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshFormat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAErG,uDAAuD;AACvD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;AAErE,yCAAyC;AACzC,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,GAAG,kBAAkB,CAInF;AAED,mFAAmF;AACnF,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAS5E;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,qBAAqB,EAAE,WAAW,UAAQ,GAAG,MAAM,EAAE,CAS/F;AAED,uCAAuC;AACvC,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAW7E"}
@@ -0,0 +1,67 @@
1
+ /** The number of reports per outcome. */
2
+ export function QueryRefreshTotalsOf(run) {
3
+ const totals = { Refreshed: 0, Unchanged: 0, NotPermitted: 0, Unavailable: 0, Failed: 0 };
4
+ for (const report of run.Reports)
5
+ totals[report.Outcome]++;
6
+ return totals;
7
+ }
8
+ /** One line summing a run up: `12 refreshed, 19 unchanged, 0 failed (dry run)`. */
9
+ export function FormatQueryRefreshSummary(run) {
10
+ const t = QueryRefreshTotalsOf(run);
11
+ const verb = run.DryRun ? 'would be refreshed' : 'refreshed';
12
+ const parts = [`${t.Refreshed} ${verb}`, `${t.Unchanged} unchanged`, `${t.Failed} failed`];
13
+ if (t.NotPermitted > 0)
14
+ parts.push(`${t.NotPermitted} skipped (not permitted)`);
15
+ if (t.Unavailable > 0)
16
+ parts.push(`${t.Unavailable} unavailable`);
17
+ const withErrors = run.Reports.filter(r => r.ExtractionStatus === 'Error').length;
18
+ if (withErrors > 0)
19
+ parts.push(`${withErrors} with extraction errors`);
20
+ return `${run.Reports.length} queries: ${parts.join(', ')}${run.DryRun ? ' (dry run: nothing was written)' : ''}.`;
21
+ }
22
+ /**
23
+ * The lines of a run's report: one heading per query, then its row changes, flagged parameters
24
+ * and diagnostics, then any composition cycles and the summary. With `changedOnly`, unchanged
25
+ * queries with no diagnostics are left out.
26
+ */
27
+ export function FormatQueryRefreshRun(run, changedOnly = false) {
28
+ const lines = [];
29
+ for (const report of run.Reports) {
30
+ if (changedOnly && report.Outcome === 'Unchanged' && report.Diagnostics.length === 0)
31
+ continue;
32
+ lines.push(...FormatQueryRefreshReport(report));
33
+ }
34
+ for (const cycle of run.Cycles)
35
+ lines.push(`Composition cycle (each refreshed once): ${cycle.join(' -> ')}`);
36
+ lines.push(FormatQueryRefreshSummary(run));
37
+ return lines;
38
+ }
39
+ /** The lines of one query's report. */
40
+ export function FormatQueryRefreshReport(report) {
41
+ const name = report.QueryName ? `"${report.QueryName}" (${report.QueryID})` : report.QueryID;
42
+ const status = report.ExtractionStatus ? ` [${report.ExtractionStatus}]` : '';
43
+ const lines = [`${outcomeLabel(report)} ${name}${status}`];
44
+ if (report.QueryColumns.length > 0)
45
+ lines.push(` ~ query (${report.QueryColumns.join(', ')})`);
46
+ for (const change of report.Added)
47
+ lines.push(` + ${changeLabel(change)}`);
48
+ for (const change of report.Updated)
49
+ lines.push(` ~ ${changeLabel(change)}${change.ChangedColumns.length > 0 ? ` (${change.ChangedColumns.join(', ')})` : ''}`);
50
+ for (const change of report.Removed)
51
+ lines.push(` - ${changeLabel(change)}`);
52
+ for (const name of report.Flagged)
53
+ lines.push(` ! parameter ${name}: authored, no longer used by the SQL (kept)`);
54
+ for (const line of report.Diagnostics)
55
+ lines.push(` ${line}`);
56
+ return lines;
57
+ }
58
+ function outcomeLabel(report) {
59
+ if (report.Outcome === 'Refreshed')
60
+ return report.DryRun ? 'WOULD REFRESH' : 'REFRESHED';
61
+ return report.Outcome.toUpperCase();
62
+ }
63
+ function changeLabel(change) {
64
+ const kind = { Fields: 'field', Parameters: 'parameter', Entities: 'entity', Dependencies: 'dependency' }[change.Collection];
65
+ return `${kind} ${change.Name}`;
66
+ }
67
+ //# sourceMappingURL=refreshFormat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshFormat.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshFormat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /** A query to order, by ID, with a name for reporting. */
2
+ export interface OrderableQuery {
3
+ readonly ID: string;
4
+ readonly Name: string;
5
+ }
6
+ /** A composition edge: `QueryID` composes `DependsOnQueryID`. */
7
+ export interface CompositionEdge {
8
+ readonly QueryID: string;
9
+ readonly DependsOnQueryID: string;
10
+ }
11
+ /** The order to refresh in, and the composition cycles found. */
12
+ export interface RefreshOrder {
13
+ readonly Order: readonly OrderableQuery[];
14
+ /** Each cycle's members, by name. */
15
+ readonly Cycles: readonly (readonly string[])[];
16
+ }
17
+ /**
18
+ * Orders `queries` so each comes after every selected query it composes (dependencies first),
19
+ * keeping the given order among queries that do not depend on each other. Queries in a
20
+ * composition cycle (stored by an older version that allowed one), and those that depend on
21
+ * them, come last in their given order; each is listed once, so a cycle is never followed round.
22
+ * Edges to queries outside the selection are ignored.
23
+ */
24
+ export declare function OrderForRefresh(queries: readonly OrderableQuery[], edges: readonly CompositionEdge[]): RefreshOrder;
25
+ //# sourceMappingURL=refreshOrder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshOrder.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshOrder.ts"],"names":[],"mappings":"AAEA,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACzB;AAED,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACrC;AAED,iEAAiE;AACjE,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;CACnD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,EAAE,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,YAAY,CAmBnH"}
@@ -0,0 +1,95 @@
1
+ import { NormalizeUUID } from "@memberjunction/global";
2
+ /**
3
+ * Orders `queries` so each comes after every selected query it composes (dependencies first),
4
+ * keeping the given order among queries that do not depend on each other. Queries in a
5
+ * composition cycle (stored by an older version that allowed one), and those that depend on
6
+ * them, come last in their given order; each is listed once, so a cycle is never followed round.
7
+ * Edges to queries outside the selection are ignored.
8
+ */
9
+ export function OrderForRefresh(queries, edges) {
10
+ const ids = queries.map(q => NormalizeUUID(q.ID));
11
+ const selected = new Set(ids);
12
+ const dependsOn = new Map(ids.map(id => [id, new Set()]));
13
+ for (const edge of edges) {
14
+ const from = NormalizeUUID(edge.QueryID);
15
+ const to = NormalizeUUID(edge.DependsOnQueryID);
16
+ if (selected.has(from) && selected.has(to) && from !== to)
17
+ dependsOn.get(from)?.add(to);
18
+ if (from === to && selected.has(from))
19
+ dependsOn.get(from)?.add(to);
20
+ }
21
+ const ordered = topologicalOrder(ids, dependsOn);
22
+ const placed = new Set(ordered);
23
+ const rest = ids.filter(id => !placed.has(id));
24
+ const byID = new Map(queries.map(q => [NormalizeUUID(q.ID), q]));
25
+ const nameOf = (id) => byID.get(id)?.Name ?? id;
26
+ return {
27
+ Order: [...ordered, ...rest].map(id => byID.get(id)).filter((q) => q !== undefined),
28
+ Cycles: findCycles(rest, dependsOn).map(cycle => cycle.map(nameOf)),
29
+ };
30
+ }
31
+ /** Kahn's algorithm, stable in the given order; nodes on or behind a cycle are left out. */
32
+ function topologicalOrder(ids, dependsOn) {
33
+ const done = new Set();
34
+ const ordered = [];
35
+ let progressed = true;
36
+ while (progressed) {
37
+ progressed = false;
38
+ for (const id of ids) {
39
+ if (done.has(id))
40
+ continue;
41
+ const deps = dependsOn.get(id) ?? new Set();
42
+ if ([...deps].every(d => done.has(d))) {
43
+ done.add(id);
44
+ ordered.push(id);
45
+ progressed = true;
46
+ }
47
+ }
48
+ }
49
+ return ordered;
50
+ }
51
+ /** The strongly connected components among `ids` that are cycles (more than one member, or a self-reference). */
52
+ function findCycles(ids, dependsOn) {
53
+ const within = new Set(ids);
54
+ const index = new Map();
55
+ const low = new Map();
56
+ const stack = [];
57
+ const onStack = new Set();
58
+ const cycles = [];
59
+ let counter = 0;
60
+ const visit = (id) => {
61
+ index.set(id, counter);
62
+ low.set(id, counter++);
63
+ stack.push(id);
64
+ onStack.add(id);
65
+ for (const dep of dependsOn.get(id) ?? []) {
66
+ if (!within.has(dep))
67
+ continue;
68
+ if (!index.has(dep)) {
69
+ visit(dep);
70
+ low.set(id, Math.min(low.get(id) ?? 0, low.get(dep) ?? 0));
71
+ }
72
+ else if (onStack.has(dep)) {
73
+ low.set(id, Math.min(low.get(id) ?? 0, index.get(dep) ?? 0));
74
+ }
75
+ }
76
+ if (low.get(id) !== index.get(id))
77
+ return;
78
+ const component = [];
79
+ let member;
80
+ do {
81
+ member = stack.pop();
82
+ if (member === undefined)
83
+ break;
84
+ onStack.delete(member);
85
+ component.push(member);
86
+ } while (member !== id);
87
+ if (component.length > 1 || dependsOn.get(id)?.has(id))
88
+ cycles.push(component.reverse());
89
+ };
90
+ for (const id of ids)
91
+ if (!index.has(id))
92
+ visit(id);
93
+ return cycles;
94
+ }
95
+ //# sourceMappingURL=refreshOrder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshOrder.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshOrder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { CompositionEdge, OrderableQuery } from "./refreshOrder.js";
2
+ import type { QueryRefreshContext, QueryRefreshFilter } from "./refreshTypes.js";
3
+ /** The queries a filter selects, the selectors that matched nothing, and the composition edges among them. */
4
+ export interface RefreshSelection {
5
+ readonly Queries: readonly OrderableQuery[];
6
+ /** Each ID or name the filter gave that matched no query the caller can read, as given. */
7
+ readonly Unmatched: readonly string[];
8
+ readonly Edges: readonly CompositionEdge[];
9
+ }
10
+ /**
11
+ * The queries `filter` selects, read as the caller from the database (never a cache), so a
12
+ * caller only ever selects queries it can read. Selectors combine as a union.
13
+ */
14
+ export declare function SelectQueriesForRefresh(context: QueryRefreshContext, filter: QueryRefreshFilter): Promise<RefreshSelection>;
15
+ //# sourceMappingURL=refreshSelection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshSelection.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshSelection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAoB9E,8GAA8G;AAC9G,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IAC5C,2FAA2F;IAC3F,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiBjI"}
@@ -0,0 +1,99 @@
1
+ import { NormalizeUUID } from "@memberjunction/global";
2
+ /**
3
+ * The queries `filter` selects, read as the caller from the database (never a cache), so a
4
+ * caller only ever selects queries it can read. Selectors combine as a union.
5
+ */
6
+ export async function SelectQueriesForRefresh(context, filter) {
7
+ const entityIDs = entityIDsOf(context, filter);
8
+ const [queries, categories, links, edges] = await readAll(context, entityIDs.length > 0);
9
+ const paths = categoryPaths(categories);
10
+ const selected = new Map();
11
+ const unmatched = [];
12
+ const add = (rows) => rows.forEach(r => selected.set(NormalizeUUID(r.ID), r));
13
+ if (filter.All)
14
+ add(queries);
15
+ for (const id of filter.QueryIDs ?? [])
16
+ collect(queries.filter(q => NormalizeUUID(q.ID) === NormalizeUUID(id)), id, add, unmatched);
17
+ for (const name of filter.QueryNames ?? [])
18
+ collect(queries.filter(q => nameMatches(q, name, paths)), name, add, unmatched);
19
+ if (filter.CategoryPath)
20
+ add(queries.filter(q => inCategory(q, filter.CategoryPath ?? '', paths)));
21
+ if (entityIDs.length > 0) {
22
+ const wanted = new Set(entityIDs.map(NormalizeUUID));
23
+ const reading = new Set(links.filter(l => wanted.has(NormalizeUUID(l.EntityID))).map(l => NormalizeUUID(l.QueryID)));
24
+ add(queries.filter(q => reading.has(NormalizeUUID(q.ID))));
25
+ }
26
+ return { Queries: [...selected.values()].map(q => ({ ID: q.ID, Name: q.Name })), Unmatched: unmatched, Edges: edges };
27
+ }
28
+ function collect(rows, given, add, unmatched) {
29
+ if (rows.length === 0)
30
+ unmatched.push(given);
31
+ else
32
+ add(rows);
33
+ }
34
+ /** The entity IDs the filter names, by ID or by name (names the catalog does not hold select nothing). */
35
+ function entityIDsOf(context, filter) {
36
+ const ids = [...(filter.EntityIDs ?? [])];
37
+ for (const name of filter.EntityNames ?? []) {
38
+ const entity = context.Provider.Entities.find(e => e.Name.trim().toLowerCase() === name.trim().toLowerCase());
39
+ if (entity)
40
+ ids.push(entity.ID);
41
+ }
42
+ return ids;
43
+ }
44
+ async function readAll(context, withLinks) {
45
+ const views = [
46
+ { EntityName: 'MJ: Queries', Fields: ['ID', 'Name', 'CategoryID'], OrderBy: 'Name', ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true },
47
+ { EntityName: 'MJ: Query Categories', Fields: ['ID', 'Name', 'ParentID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true },
48
+ { EntityName: 'MJ: Query Dependencies', Fields: ['QueryID', 'DependsOnQueryID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true },
49
+ ];
50
+ if (withLinks)
51
+ views.push({ EntityName: 'MJ: Query Entities', Fields: ['QueryID', 'EntityID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true });
52
+ const results = await context.Provider.RunViews(views, context.User);
53
+ const failed = results.find(r => !r?.Success);
54
+ if (failed)
55
+ throw new Error(`the queries to refresh could not be read: ${failed.ErrorMessage}`);
56
+ const rows = (i) => (results[i]?.Results ?? []);
57
+ return [rows(0), rows(1), withLinks ? rows(3) : [], rows(2)];
58
+ }
59
+ /** Each category's full path (`Parent/Child`), lower-cased, by normalized ID. */
60
+ function categoryPaths(categories) {
61
+ const byID = new Map(categories.map(c => [NormalizeUUID(c.ID), c]));
62
+ const paths = new Map();
63
+ const pathOf = (id, depth) => {
64
+ const known = paths.get(id);
65
+ if (known !== undefined)
66
+ return known;
67
+ const category = byID.get(id);
68
+ if (!category)
69
+ return '';
70
+ const parent = category.ParentID && depth < 64 ? pathOf(NormalizeUUID(category.ParentID), depth + 1) : '';
71
+ const path = (parent ? `${parent}/${category.Name.trim()}` : category.Name.trim()).toLowerCase();
72
+ paths.set(id, path);
73
+ return path;
74
+ };
75
+ for (const id of byID.keys())
76
+ pathOf(id, 0);
77
+ return paths;
78
+ }
79
+ function normalizePath(path) {
80
+ return path.split('/').map(s => s.trim()).filter(s => s.length > 0).join('/').toLowerCase();
81
+ }
82
+ function pathOfQuery(query, paths) {
83
+ return query.CategoryID ? paths.get(NormalizeUUID(query.CategoryID)) ?? '' : '';
84
+ }
85
+ /** A bare name matches every query with that name; a path matches the query at that full path. */
86
+ function nameMatches(query, given, paths) {
87
+ const wanted = normalizePath(given);
88
+ const name = query.Name.trim().toLowerCase();
89
+ if (!given.includes('/'))
90
+ return name === wanted;
91
+ const category = pathOfQuery(query, paths);
92
+ return (category ? `${category}/${name}` : name) === wanted;
93
+ }
94
+ function inCategory(query, categoryPath, paths) {
95
+ const wanted = normalizePath(categoryPath);
96
+ const category = pathOfQuery(query, paths);
97
+ return wanted.length > 0 && (category === wanted || category.startsWith(`${wanted}/`));
98
+ }
99
+ //# sourceMappingURL=refreshSelection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshSelection.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshSelection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import type { IMetadataProvider, IRunViewProvider, UserInfo } from "@memberjunction/core";
2
+ import type { ChildRowChange, QueryExtractionStatus } from "../query-extraction/index.js";
3
+ /** The provider a refresh reads and writes through: the caller's, so its transaction and permissions apply. */
4
+ export type QueryRefreshProvider = IMetadataProvider & IRunViewProvider;
5
+ /**
6
+ * Which saved queries a bulk refresh covers. Selectors combine as a union; `All` selects every
7
+ * query the caller can read. A refresh with no selector refreshes nothing.
8
+ */
9
+ export interface QueryRefreshFilter {
10
+ /** Query IDs. */
11
+ readonly QueryIDs?: readonly string[];
12
+ /** Query names, or full paths (`Category/Sub/Name`); a bare name selects every query with that name. */
13
+ readonly QueryNames?: readonly string[];
14
+ /** A category path (`Category/Sub`): the queries in that category and every category below it. */
15
+ readonly CategoryPath?: string;
16
+ /** Entity names: the queries that read any of these entities (their `MJ: Query Entities` rows). */
17
+ readonly EntityNames?: readonly string[];
18
+ /** Entity IDs, as {@link EntityNames}. */
19
+ readonly EntityIDs?: readonly string[];
20
+ /** Every query. */
21
+ readonly All?: boolean;
22
+ }
23
+ /** How a refresh runs. */
24
+ export interface QueryRefreshOptions {
25
+ /** Work out and report the changes without writing anything. */
26
+ readonly DryRun?: boolean;
27
+ /** Queue the LLM description pass for rows still without a description (off by default). */
28
+ readonly WithAI?: boolean;
29
+ /** Called once per query as a bulk refresh finishes it. */
30
+ readonly OnProgress?: (progress: QueryRefreshProgress) => void;
31
+ }
32
+ /** A bulk refresh's progress after one query. */
33
+ export interface QueryRefreshProgress {
34
+ readonly Processed: number;
35
+ readonly Total: number;
36
+ readonly Report: QueryRefreshReport;
37
+ }
38
+ /**
39
+ * What happened to one query:
40
+ * - `Refreshed`: the child rows or the query's extraction columns changed (with `DryRun`: would change);
41
+ * - `Unchanged`: the stored rows already match the SQL;
42
+ * - `NotPermitted`: a bulk refresh skipped a query the caller may not refresh (no reason is given);
43
+ * - `Unavailable`: the query does not exist or the caller may not refresh it (the two read alike);
44
+ * - `Failed`: the refresh could not be completed, and nothing was written.
45
+ */
46
+ export type QueryRefreshOutcome = 'Refreshed' | 'Unchanged' | 'NotPermitted' | 'Unavailable' | 'Failed';
47
+ /** One query's refresh. */
48
+ export interface QueryRefreshReport {
49
+ /** The query's ID; for `Unavailable`, the identifier the caller supplied. */
50
+ readonly QueryID: string;
51
+ /** The query's name; empty for `Unavailable`. */
52
+ readonly QueryName: string;
53
+ readonly Outcome: QueryRefreshOutcome;
54
+ readonly DryRun: boolean;
55
+ /** The extraction status the run records (or, with `DryRun`, would record); `null` when it did not run. */
56
+ readonly ExtractionStatus: QueryExtractionStatus | null;
57
+ /** The columns of the query row itself the run changes (`UsesTemplate`, `ExtractedSQLHash`, `ExtractionStatus`, `ExtractionMessage`). */
58
+ readonly QueryColumns: readonly string[];
59
+ readonly Added: readonly ChildRowChange[];
60
+ readonly Updated: readonly ChildRowChange[];
61
+ readonly Removed: readonly ChildRowChange[];
62
+ /** Authored parameters the SQL no longer uses: kept, and flagged on the query. */
63
+ readonly Flagged: readonly string[];
64
+ /** The run's diagnostics (`ExtractionMessage` lines), or why it was not completed. */
65
+ readonly Diagnostics: readonly string[];
66
+ }
67
+ /** A bulk refresh: one report per query, in the order the queries were refreshed. */
68
+ export interface QueryRefreshRunReport {
69
+ readonly DryRun: boolean;
70
+ readonly Reports: readonly QueryRefreshReport[];
71
+ /** Queries that compose each other in a cycle, by name; each was refreshed once, after the rest. */
72
+ readonly Cycles: readonly (readonly string[])[];
73
+ }
74
+ /** Who a refresh runs as and through which provider. */
75
+ export interface QueryRefreshContext {
76
+ readonly Provider: QueryRefreshProvider;
77
+ readonly User: UserInfo;
78
+ }
79
+ /** Whether `provider` can read views and create entity objects, which is everything a refresh needs. */
80
+ export declare function IsQueryRefreshProvider(provider: IMetadataProvider): provider is QueryRefreshProvider;
81
+ //# sourceMappingURL=refreshTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshTypes.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshTypes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Whether `provider` can read views and create entity objects, which is everything a refresh needs. */
2
+ export function IsQueryRefreshProvider(provider) {
3
+ return typeof Reflect.get(provider, 'RunViews') === 'function' && typeof Reflect.get(provider, 'RunView') === 'function';
4
+ }
5
+ //# sourceMappingURL=refreshTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refreshTypes.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/refreshTypes.ts"],"names":[],"mappings":"AAuFA,wGAAwG;AACxG,MAAM,UAAU,sBAAsB,CAAC,QAA2B;IAC9D,OAAO,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,KAAK,UAAU,IAAI,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,UAAU,CAAC;AAC7H,CAAC"}
@@ -6,4 +6,12 @@ import { BaseEntity, SimpleEmbeddingResult } from "@memberjunction/core";
6
6
  * @returns
7
7
  */
8
8
  export declare function EmbedTextLocalHelper(entity: BaseEntity, textToEmbed: string): Promise<SimpleEmbeddingResult>;
9
+ /**
10
+ * `BaseEntity.IsEmbeddingStale` for entities that embed with {@link EmbedTextLocalHelper}: a stored
11
+ * vector is stale when it came from a model other than the platform's default local embedding model
12
+ * (`AIEngine.DefaultLocalEmbeddingModel`), or from an unrecorded one.
13
+ * @param entity
14
+ * @param embeddingModelID - The stored vector's model ID, or null
15
+ */
16
+ export declare function IsLocalEmbeddingStaleHelper(entity: BaseEntity, embeddingModelID: string | null): Promise<boolean>;
9
17
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/custom/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAEzE;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAYlH"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/custom/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAEzE;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAYlH;AAED;;;;;;GAMG;AACH,wBAAsB,2BAA2B,CAAC,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CASvH"}
@@ -7,7 +7,7 @@ import { AIEngine } from "@memberjunction/aiengine";
7
7
  */
8
8
  export async function EmbedTextLocalHelper(entity, textToEmbed) {
9
9
  await AIEngine.Instance.Config(false, entity.ContextCurrentUser);
10
- const e = await AIEngine.Instance.EmbedTextLocal(textToEmbed);
10
+ const e = await AIEngine.Instance.EmbedTextLocal(textToEmbed, { inputType: 'document' });
11
11
  if (!e?.result?.vector || !e?.model?.ID) {
12
12
  throw new Error('Failed to generate embedding - no vector or model ID returned');
13
13
  }
@@ -16,4 +16,21 @@ export async function EmbedTextLocalHelper(entity, textToEmbed) {
16
16
  modelID: e.model.ID
17
17
  };
18
18
  }
19
+ /**
20
+ * `BaseEntity.IsEmbeddingStale` for entities that embed with {@link EmbedTextLocalHelper}: a stored
21
+ * vector is stale when it came from a model other than the platform's default local embedding model
22
+ * (`AIEngine.DefaultLocalEmbeddingModel`), or from an unrecorded one.
23
+ * @param entity
24
+ * @param embeddingModelID - The stored vector's model ID, or null
25
+ */
26
+ export async function IsLocalEmbeddingStaleHelper(entity, embeddingModelID) {
27
+ await AIEngine.Instance.Config(false, entity.ContextCurrentUser);
28
+ // With no local embedding model there is nothing to re-embed with, so nothing is stale. (Treating
29
+ // everything as stale would make every save try, and fail, to embed — and a tag saved by TagEngine
30
+ // with a hosted model would have its vector cleared by its own save hook.)
31
+ if (!AIEngine.Instance.DefaultLocalEmbeddingModel) {
32
+ return false;
33
+ }
34
+ return !AIEngine.Instance.IsDefaultLocalEmbeddingModel(embeddingModelID);
35
+ }
19
36
  //# sourceMappingURL=util.js.map